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
12 changes: 12 additions & 0 deletions .github/workflows/Prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,19 @@ jobs:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
id: get_version
run: node ./Update/GetVersion.js
# 版本号没变(例如合并了没有更新版本号的 PR)时,不能把已发布的正式版覆盖成预发布版;同版本的预发布版照常更新
- name: Check for an existing release
id: existing_release
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
VERSION: ${{ steps.get_version.outputs.version }}
run: |
if [ "$(gh release view "$VERSION" --json isPrerelease --jq .isPrerelease 2>/dev/null)" = "false" ]; then
echo "Release $VERSION is already published as a stable release, skipping the prerelease."
echo exists=true >> $GITHUB_OUTPUT
fi
- id: create_release
if: steps.existing_release.outputs.exists != 'true'
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
Expand Down
18 changes: 14 additions & 4 deletions .github/workflows/UpdateToRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,34 @@ on:
jobs:
UpdateToRelease:
runs-on: ubuntu-latest
# 添加条件:如果是 bot 触发的则跳过,避免无限循环
if: github.event.pull_request.user.login != 'github-actions[bot]'
# 添加条件:如果是 bot 触发的则跳过,避免无限循环;fork 的 PR 拿不到 secrets,也跳过
if: github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.login != 'github-actions[bot]'
permissions:
pull-requests: write
contents: write
steps:
# 用 GitHub App 的 token 创建版本 PR,这样它的工作流无需手动批准就能运行并自动合并
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.APP_ID }}
Comment thread
boomzero marked this conversation as resolved.
private-key: ${{ secrets.APP_PRIVATE_KEY }}
Comment thread
boomzero marked this conversation as resolved.
permission-contents: write
permission-pull-requests: write
- uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ steps.generate_token.outputs.token }}
- name: Update to release
run: |
if [[ ${{ github.event.pull_request.head.ref }} != dev && $(git diff --name-only HEAD HEAD~1) == *XMOJ.user.js* ]]; then
echo Closing PR
gh pr comment ${{ github.event.pull_request.number }} --body "请向\`dev\`分支提交pull request, 本pull request将被自动关闭"
gh pr close ${{ github.event.pull_request.number }}
else
node ./Update/UpdateToRelease.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.pull_request.number }} "$PR_BODY"
node ./Update/UpdateToRelease.js ${{ steps.generate_token.outputs.token }} ${{ github.event.pull_request.number }} "$PR_BODY"
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
PR_BODY: ${{ github.event.pull_request.body }}
7 changes: 6 additions & 1 deletion .github/workflows/UpdateVersion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ jobs:
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v6
- name: Update version
# PR 标题不可信,通过环境变量传入,不直接拼进 shell 命令
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
PR_NUMBER: ${{ github.event.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}" "$PR_BODY" "${{ github.event.action }}"
PR_ACTION: ${{ github.event.action }}
run: node ./Update/UpdateVersion.js "$GITHUB_TOKEN" "$PR_NUMBER" "$PR_TITLE" "$PR_BODY" "$PR_ACTION"
54 changes: 54 additions & 0 deletions .github/workflows/UpdateVersionFork.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: UpdateVersionFork
# fork 的 PR 拿不到 secrets,也不能推送到 fork,所以合并前没法更新版本号。
# 维护者合并后会推送到 dev:在这次(可信的)推送上找出所有已合并、但 Update.json 里还没有记录的 fork PR,
# 逐个基于最新的 dev 更新版本号,并以 GitHub App 身份开自动合并的 PR,等它合并后再处理下一个。
# 并发组最多保留一个排队的运行,被替换掉的运行要处理的 PR 也会被后面的运行补上。
on:
push:
branches:
- dev
paths:
- XMOJ.user.js
workflow_dispatch:
concurrency:
group: update-version-fork
Comment thread
boomzero marked this conversation as resolved.
cancel-in-progress: false
jobs:
UpdateVersionFork:
runs-on: ubuntu-latest
if: ${{ !endsWith(github.actor, '[bot]') }}
permissions:
contents: read
steps:
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- uses: actions/checkout@v6
with:
ref: dev
token: ${{ steps.generate_token.outputs.token }}
- name: Update versions of merged fork PRs
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
REPOSITORY: ${{ github.repository }}
# 在此之前合并的 fork PR 不再补记版本号
SINCE: "2026-10-06T00:00:00Z"
run: |
PRS=$(gh pr list --repo "$REPOSITORY" --base dev --state merged --limit 50 --json number,isCrossRepository,mergedAt \
--jq "map(select(.isCrossRepository and .mergedAt >= \"$SINCE\")) | sort_by(.mergedAt) | .[].number")
for PR_NUMBER in $PRS; do
git fetch -q origin dev
git checkout -q -B dev origin/dev
if jq -e --argjson pr "$PR_NUMBER" '[.UpdateHistory[].UpdateContents[].PR] | index($pr)' Update.json > /dev/null; then
echo "#$PR_NUMBER already has a version."
continue
fi
PR_TITLE=$(gh api "repos/$REPOSITORY/pulls/$PR_NUMBER" --jq .title)
PR_BODY=$(gh api "repos/$REPOSITORY/pulls/$PR_NUMBER" --jq '.body // ""')
node ./Update/UpdateVersion.js "$GITHUB_TOKEN" "$PR_NUMBER" "$PR_TITLE" "$PR_BODY" fork-merged
done
25 changes: 0 additions & 25 deletions .github/workflows/main.yml

This file was deleted.

51 changes: 0 additions & 51 deletions .github/workflows/merge.yml

This file was deleted.

24 changes: 0 additions & 24 deletions .github/workflows/sync-to-extern-contrib.yml

This file was deleted.

7 changes: 3 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ Use: Task tool with xmoj-code-navigator agent to find specific sections
### Branch Structure and PR Requirements

- `master`: Production branch - **DO NOT make PRs directly to master**
- `dev`: Development branch - **ALL PRs must be based on and target this branch**
- `extern-contrib`: External contributors must submit PRs to this branch
- `dev`: Development branch - **ALL PRs must be based on and target this branch**, including PRs from forks

**CRITICAL: All pull requests must:**
1. Be based on the `dev` branch (branch off from `dev`)
Expand Down Expand Up @@ -191,10 +190,10 @@ If you see "XMOJ.user.js and Update.json have different patch versions":
### PR Requirements

- **All PRs must be based on and target `dev` branch, not `master`**
- Only PRs from the same repository (not forks) trigger auto-versioning
- Only PRs from the same repository trigger UpdateVersion before merge. Fork PRs get no secrets, so after a fork PR merges, `UpdateVersionFork` (on the push to `dev`) bumps the version on `actions/version-<PR>` and opens an auto-merging PR
- PRs must modify `XMOJ.user.js` to trigger version bumps
- Must merge `dev` into your branch before submitting
- External contributors must target `extern-contrib` branch
- External contributors fork the repo and target `dev` too

### Single-File Architecture

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ We are happy to have you here with us!
We believe that you must be excited to contribute to our repo, but first, please read the contribution guidelines!

> [!IMPORTANT]
> 请注意, 外部开发者应向`extern-contrib`提交 pull requests。
> 请向 `dev` 分支提交 pull requests。外部开发者请先 fork 本仓库,从 `dev` 拉分支,再向本仓库的 `dev` 提 PR。版本号由维护者和 CI 更新,不要手动修改。

- Our goal for `xmoj-script` is **stability before features**. This means we focus on squashing critical bugs before adding new features. Often, we can do both in tandem, but bugs will take priority over a new feature.
- We use Bootstrap in our project. Please use Bootstrap classes instead of writing your own CSS whenever possible.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
链接戳[这里](https://opencollective.com/xmoj-script-dev)。

> [!IMPORTANT]
> 请注意, 外部开发者应向`extern-contrib`提交 pull requests。
> 请向 `dev` 分支提交 pull requests。外部开发者请先 fork 本仓库,从 `dev` 拉分支,再向本仓库的 `dev` 提 PR。版本号由维护者和 CI 更新,不要手动修改。

## Contributors

Expand Down
2 changes: 1 addition & 1 deletion Update.json
Original file line number Diff line number Diff line change
Expand Up @@ -3904,7 +3904,7 @@
"Description": "Fix image enlarger and minimalist skin on video replay pages; add page title"
}
],
"Notes": "- 修复回放视频进度条拖动球被当作图片放大的问题\n- 修复极简黑白界面下视频播放器按钮出现灰色方框的问题\n- 回放页面增加页面标题"
"Notes": "<ul><li>修复回放视频进度条拖动球被当作图片放大的问题</li><li>修复极简黑白界面下视频播放器按钮出现灰色方框的问题</li><li>回放页面增加页面标题</li></ul>"
},
"3.9.0": {
"UpdateDate": 1791249917714,
Expand Down
65 changes: 52 additions & 13 deletions Update/UpdateVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,29 @@ import {execSync} from "child_process";
var GithubToken = process.argv[2];
var PRNumber = process.argv[3];
process.env.GITHUB_TOKEN = GithubToken;
execSync("gh pr checkout " + PRNumber);
console.info("PR #" + PRNumber + " has been checked out.");

// Check if the last commit was made by github-actions[bot]
// Only skip for synchronize events (push-triggered) to prevent infinite loops.
// For edited events (PR title/body changes), allow metadata updates even when
// the branch tip is a bot commit.
const eventAction = String(process.argv[6] || "");
const lastCommitAuthor = execSync("git log -1 --pretty=format:'%an'").toString().trim();
console.log("Last commit author: " + lastCommitAuthor);
// A merged PR from a fork: we cannot push to the fork, so bump the version on
// a branch of this repository (checked out at dev) and open an auto-merging PR.
const ForkMerged = eventAction === "fork-merged";
const ForkBranch = "actions/version-" + Number(PRNumber);
console.log("Event action : " + eventAction);
if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {
console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop.");
process.exit(0);
if (ForkMerged) {
execSync("git checkout -B " + ForkBranch);
Comment thread
boomzero marked this conversation as resolved.
console.info("Bumping the version for merged fork PR #" + PRNumber + " on " + ForkBranch + ".");
} else {
execSync("gh pr checkout " + PRNumber);
console.info("PR #" + PRNumber + " has been checked out.");

// Check if the last commit was made by github-actions[bot]
// Only skip for synchronize events (push-triggered) to prevent infinite loops.
// For edited events (PR title/body changes), allow metadata updates even when
// the branch tip is a bot commit.
const lastCommitAuthor = execSync("git log -1 --pretty=format:'%an'").toString().trim();
console.log("Last commit author: " + lastCommitAuthor);
if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {
console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop.");
process.exit(0);
}
}

const JSONFileName = "./Update.json";
Expand All @@ -26,7 +35,10 @@ var JSONFileContent = readFileSync(JSONFileName, "utf8");
var JSFileContent = readFileSync(JSFileName, "utf8");
execSync("git config --global user.email \"github-actions[bot]@users.noreply.github.com\"");
execSync("git config --global user.name \"github-actions[bot]\"");
if (JSONFileContent.includes('//!ci-no-touch')) {
if (ForkMerged && JSONFileContent.includes('//!ci-no-touch')) {
// The marker only means something on an open PR branch.
JSONFileContent = JSONFileContent.replace('//!ci-no-touch', '');
} else if (JSONFileContent.includes('//!ci-no-touch')) {
var updatedContent = JSONFileContent.replace('//!ci-no-touch', '');
writeFileSync(JSONFileName, updatedContent, "utf8");
execSync("git config pull.rebase false");
Expand Down Expand Up @@ -115,6 +127,33 @@ writeFileSync(JSONFileName, JSON.stringify(JSONObject, null, 4), "utf8");

console.warn("Update.json has been updated.");

if (ForkMerged) {
execSync("git commit -a -m \"" + CommitMessage + "\"");
execSync("git push -u origin " + ForkBranch + " -f");
console.log("Pushed to " + ForkBranch + ".");
// A rerun may find the PR from an earlier attempt; reuse it instead of failing to create a duplicate.
var VersionPR = execSync("gh pr list --base dev --head " + ForkBranch + " --state open --json url --jq '.[0].url // empty'").toString().trim();
if (VersionPR) {
console.log("Reusing " + VersionPR + ".");
} else {
VersionPR = execSync("gh pr create --base dev --head " + ForkBranch + " --title \"" + CommitMessage + " (#" + CurrentPR + ")\" --body \"Version bump for fork PR #" + CurrentPR + ".\"").toString().trim();
console.log("Created " + VersionPR + ".");
}
execSync("gh pr merge " + VersionPR + " --merge --auto");
console.log("Enabled auto merge.");
// Wait for the merge, so the next fork PR is bumped from a dev that already has this version.
for (var Attempt = 0; ; Attempt++) {
var State = execSync("gh pr view " + VersionPR + " --json state --jq .state").toString().trim();
if (State == "MERGED") break;
if (State == "CLOSED" || Attempt >= 120) {
console.error(VersionPR + " was not merged (state: " + State + ").");
process.exit(1);
}
execSync("sleep 10");
}
console.log(VersionPR + " has been merged.");
process.exit(0);
}
execSync("git config pull.rebase false");
execSync("git pull");
execSync("git commit -a -m \"" + CommitMessage + "\"");
Expand Down
2 changes: 1 addition & 1 deletion child-protection.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ <h2>我们收集得很少</h2>
<h2>请家长留意</h2>
<ul>
<li>讨论区的帖子所有用户都能看到,上传的图片拿到链接的人都能打开。提醒孩子不要在帖子或图片里透露真实姓名、学校、联系方式、人脸等个人信息。</li>
<li>短消息只有收发双方能看到,加密保存,管理员也看不到内容。如果孩子收到骚扰或不当内容,请截图后联系我们处理。</li>
<li>短消息显示给收发双方,数据库加密保存;管理员不修改服务器代码就看不到内容,但这不是端到端加密,解密在服务器上完成。如果孩子收到骚扰或不当内容,请截图后联系我们处理。</li>
</ul>

<h2>申请删除</h2>
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ <h3 class="h5">报告问题</h3>
</div>
<div class="col-md-4">
<h3 class="h5">贡献代码</h3>
<p class="mb-0">欢迎 PR。外部贡献者请提交到 <code>extern-contrib</code> 分支,详见<a href="https://github.com/XMOJ-Script-dev/XMOJ-Script/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer">贡献指南</a>。</p>
<p class="mb-0">欢迎 PR。fork 本仓库后向 <code>dev</code> 分支提交,详见<a href="https://github.com/XMOJ-Script-dev/XMOJ-Script/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer">贡献指南</a>。</p>
</div>
<div class="col-md-4">
<h3 class="h5">赞助</h3>
Expand Down
Loading
Loading