mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-22 20:35:20 +00:00
feat: create git tag automatically to trigger releases (#1951)
This PR introduces multiple GitHub Actions to automate the release
procedure. In brief, it contains:
- **For nightly releases**: A fully automated GitHub Action that updates
dependencies (including dependencies of typstyle, typst.ts, and
typst-ansi-hl), releases nightly RC (aka canary version in the action
script) and nightly builds, along with its helper script (which can also
be useful for manually updating versions).
- **For stable releases**: Two GitHub Actions, one that detects newly
opened PRs containing tagging directives (`+Tag vx.y.z-rcw`) and leaves
comments, and another that detects merged tagging PRs and performs the
actual tagging.
Examples:
- Nightly release:
4708018995
- Stable release: ParaN3xus/tinymist#1, ParaN3xus/tinymist#2
Extra work needed to merge this PR:
- [ ] Remove all `nightly/*` branches and create `nightly` branch
- [ ] Add `NIGHTLY_REPO_TOKEN` secret to this repo
---------
Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
This commit is contained in:
parent
9f7c21bb0c
commit
3aa9c9def0
6 changed files with 1161 additions and 1 deletions
149
.github/workflows/auto-tag.yml
vendored
Normal file
149
.github/workflows/auto-tag.yml
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
name: tinymist::auto_tag
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
auto-tag:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get merged PR info
|
||||
id: get-pr
|
||||
run: |
|
||||
COMMIT_SHA="${{ github.sha }}"
|
||||
|
||||
PR_NUMBER=$(gh pr list --state merged --limit 50 --json number,mergeCommit \
|
||||
--jq ".[] | select(.mergeCommit.oid == \"$COMMIT_SHA\") | .number")
|
||||
|
||||
if [ -n "$PR_NUMBER" ]; then
|
||||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "Found merged PR: #$PR_NUMBER"
|
||||
else
|
||||
echo "pr_number=" >> $GITHUB_OUTPUT
|
||||
echo "No merged PR found for this commit"
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check for tag directive in merged PR
|
||||
if: steps.get-pr.outputs.pr_number != ''
|
||||
id: check-tag
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = '${{ steps.get-pr.outputs.pr_number }}';
|
||||
|
||||
if (!prNumber) {
|
||||
console.log('No PR number found');
|
||||
core.setOutput('tag_found', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: parseInt(prNumber)
|
||||
});
|
||||
|
||||
const prBody = pr.body || '';
|
||||
console.log('PR Body:', prBody);
|
||||
|
||||
const tagRegex = /\+tag\s+(v\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?)/;
|
||||
const match = prBody.match(tagRegex);
|
||||
|
||||
if (match) {
|
||||
const tagVersion = match[1];
|
||||
console.log('Found tag directive:', tagVersion);
|
||||
|
||||
core.setOutput('tag_found', 'true');
|
||||
core.setOutput('tag_version', tagVersion);
|
||||
} else {
|
||||
console.log('No tag directive found in merged PR');
|
||||
core.setOutput('tag_found', 'false');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching PR:', error);
|
||||
core.setOutput('tag_found', 'false');
|
||||
}
|
||||
|
||||
- name: Check if tag already exists
|
||||
if: steps.check-tag.outputs.tag_found == 'true'
|
||||
id: check-existing-tag
|
||||
run: |
|
||||
TAG="${{ steps.check-tag.outputs.tag_version }}"
|
||||
|
||||
if git tag -l | grep -q "^$TAG$"; then
|
||||
echo "tag_exists=true" >> $GITHUB_OUTPUT
|
||||
echo "Tag $TAG already exists"
|
||||
else
|
||||
echo "tag_exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Tag $TAG does not exist, safe to create"
|
||||
fi
|
||||
|
||||
- name: Create tag
|
||||
if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'false'
|
||||
run: |
|
||||
TAG="${{ steps.check-tag.outputs.tag_version }}"
|
||||
PR_NUMBER="${{ steps.get-pr.outputs.pr_number }}"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
git tag -a "$TAG" -m "Auto-created tag $TAG from PR #$PR_NUMBER"
|
||||
git push origin "$TAG"
|
||||
|
||||
echo "Created and pushed tag: $TAG"
|
||||
|
||||
- name: Comment on merged PR
|
||||
if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'false'
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const tagVersion = '${{ steps.check-tag.outputs.tag_version }}';
|
||||
const prNumber = '${{ steps.get-pr.outputs.pr_number }}';
|
||||
|
||||
const comment = `**Tag Created Successfully**
|
||||
|
||||
Tag \`${tagVersion}\` has been automatically created and pushed to the repository following the merge of this PR.
|
||||
|
||||
You can view the tag here: https://github.com/${{ github.repository }}/releases/tag/${tagVersion}`;
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: parseInt(prNumber),
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
|
||||
- name: Handle tag creation error
|
||||
if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'true'
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const tagVersion = '${{ steps.check-tag.outputs.tag_version }}';
|
||||
const prNumber = '${{ steps.get-pr.outputs.pr_number }}';
|
||||
const actionUrl = `${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`;
|
||||
|
||||
const comment = `**Tag Creation Failed**
|
||||
|
||||
Could not create tag \`${tagVersion}\`.
|
||||
|
||||
Please refer to [this action run](${actionUrl}) for more information.`;
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: parseInt(prNumber),
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
62
.github/workflows/detect-pr-tag.yml
vendored
Normal file
62
.github/workflows/detect-pr-tag.yml
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
name: tinymist::detect_pr_tag
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
detect-tag:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check tag in PR body
|
||||
id: check-tag
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prBody = context.payload.pull_request.body || '';
|
||||
console.log('PR Body:', prBody);
|
||||
|
||||
const tagRegex = /\+tag\s+(v\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?)/;
|
||||
const match = prBody.match(tagRegex);
|
||||
|
||||
if (match) {
|
||||
const tagVersion = match[1];
|
||||
console.log('Found tag:', tagVersion);
|
||||
|
||||
core.setOutput('tag_found', 'true');
|
||||
core.setOutput('tag_version', tagVersion);
|
||||
} else {
|
||||
console.log('No tag found in PR description');
|
||||
core.setOutput('tag_found', 'false');
|
||||
}
|
||||
|
||||
- name: Comment on PR
|
||||
if: steps.check-tag.outputs.tag_found == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const tagVersion = '${{ steps.check-tag.outputs.tag_version }}';
|
||||
const comment = `**Tag Detection Notice**
|
||||
|
||||
This PR contains a tag directive: \`+tag ${tagVersion}\`
|
||||
|
||||
If this PR is merged, it will automatically create tag \`${tagVersion}\` on the main branch.
|
||||
|
||||
Please ensure before merging:
|
||||
- [ ] **Cargo.toml & Cargo.lock**: No \`git\` dependencies with \`branch\`, use \`tag\` or \`rev\` dependencies instead
|
||||
- [ ] **Publish tokens**: Both \`VSCODE_MARKETPLACE_TOKEN\` and \`OPENVSX_ACCESS_TOKEN\` are valid and not expired
|
||||
- [ ] **Version updates**: All version numbers in \`Cargo.toml\`, \`package.json\` and other files have been updated consistently
|
||||
- [ ] **Changelog**: \`editors/vscode/CHANGELOG.md\` has been updated with correct format
|
||||
- [ ] **tinymist-assets**: If needed, the crate has been published and version updated in \`Cargo.toml\`
|
||||
`
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
343
.github/workflows/release-nightly.yml
vendored
Normal file
343
.github/workflows/release-nightly.yml
vendored
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
name: Nightly Release
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
- cron: '0 23 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type'
|
||||
required: true
|
||||
default: 'nightly'
|
||||
type: choice
|
||||
options:
|
||||
- nightly
|
||||
- canary
|
||||
|
||||
jobs:
|
||||
check-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: nightly
|
||||
token: ${{ secrets.NIGHTLY_REPO_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: 'yarn'
|
||||
- name: Install deps
|
||||
run: yarn install
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.name "GitHub Actions"
|
||||
git config --global user.email "actions@github.com"
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq --no-install-recommends
|
||||
|
||||
- name: Determine release type
|
||||
id: release_type
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "schedule" ]]; then
|
||||
if [[ "${{ github.event.schedule }}" == "0 0 * * *" ]]; then
|
||||
echo "release_type=nightly" >> $GITHUB_ENV
|
||||
else
|
||||
echo "release_type=canary" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
echo "release_type=${{ github.event.inputs.release_type }}" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Check for updates
|
||||
id: check_updates
|
||||
run: |
|
||||
echo "Checking for updates in dependency repositories..."
|
||||
|
||||
# Get current revs using script
|
||||
eval "$(node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . get-current-revs)"
|
||||
|
||||
# Get latest revs
|
||||
latest_typst_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst/commits/nightly-content-hint" | jq -r '.sha')
|
||||
latest_reflexo_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst.ts/commits/nightly" | jq -r '.sha')
|
||||
latest_typstyle_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typstyle/commits/nightly" | jq -r '.sha')
|
||||
latest_typst_ansi_hl_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst-ansi-hl/commits/nightly" | jq -r '.sha')
|
||||
|
||||
echo "Current revs: typst=$current_typst_rev, typst.ts=$current_reflexo_rev, typstyle=$current_typstyle_rev, hl=$current_typst_ansi_hl_rev"
|
||||
echo "Latest revs: typst=$latest_typst_rev, typst.ts=$latest_reflexo_rev, typstyle=$latest_typstyle_rev, hl=$latest_typst_ansi_hl_rev"
|
||||
|
||||
# Check for updates
|
||||
need_update=false
|
||||
if [[ "$current_typst_rev" != "$latest_typst_rev" ]] || [[ -z "$current_typst_rev" ]]; then
|
||||
echo "Typst needs update"
|
||||
need_update=true
|
||||
fi
|
||||
if [[ "$current_reflexo_rev" != "$latest_reflexo_rev" ]] || [[ -z "$current_reflexo_rev" ]]; then
|
||||
echo "Typst.ts needs update"
|
||||
need_update=true
|
||||
fi
|
||||
if [[ "$current_typstyle_rev" != "$latest_typstyle_rev" ]] || [[ -z "$current_typstyle_rev" ]]; then
|
||||
echo "Typstyle needs update"
|
||||
need_update=true
|
||||
fi
|
||||
if [[ "$current_typst_ansi_hl_rev" != "$latest_typst_ansi_hl_rev" ]] || [[ -z "$current_typst_ansi_hl_rev" ]]; then
|
||||
echo "Typst-ansi-hl needs update"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
current_version=$(grep '^version = ' Cargo.toml | head -1 | cut -d'"' -f2)
|
||||
echo "current_version=$current_version" >> $GITHUB_ENV
|
||||
|
||||
# Updates can only be performed when releasing an RC.
|
||||
# When an RC has been released and there are no subsequent updates,
|
||||
# this indicates that the RC release was successful. Only at this
|
||||
# point will the nightly release be published.
|
||||
|
||||
need_release=false
|
||||
if [ "$release_type" = "nightly" ]; then
|
||||
if [ "$need_update" = "false" ] && echo "$current_version" | grep -q -- '-rc[0-9]\+$'; then
|
||||
echo "RC version detected with no updates needed, nightly release condition met"
|
||||
need_release=true
|
||||
else
|
||||
echo "Nightly release condition not met (requires stable RC version)"
|
||||
fi
|
||||
elif [ "$release_type" = "canary" ]; then
|
||||
if [ "$need_update" = "true" ]; then
|
||||
echo "Code updates detected, canary release condition met"
|
||||
need_release=true
|
||||
else
|
||||
echo "No code updates, skipping canary release"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Final decision: need_release=$need_release"
|
||||
|
||||
echo "need_release=$need_release" >> $GITHUB_OUTPUT
|
||||
echo "latest_typst_rev=$latest_typst_rev" >> $GITHUB_ENV
|
||||
|
||||
- name: Calculate new version
|
||||
id: version
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
echo "Current version: $current_version"
|
||||
echo "Release type: $release_type"
|
||||
|
||||
new_version=$(node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . calculate-version "$current_version" "$release_type")
|
||||
|
||||
echo "New version: $new_version"
|
||||
echo "new_version=$new_version" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Get typst information
|
||||
id: typst_info
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
# Clone typst repository
|
||||
git clone --depth 50 --single-branch --branch nightly-content-hint \
|
||||
--filter=blob:limit=1k https://github.com/ParaN3xus/typst.git /tmp/typst
|
||||
cd /tmp/typst
|
||||
git checkout nightly-content-hint
|
||||
|
||||
# Get version
|
||||
typst_version=$(grep '^version = ' Cargo.toml | head -1 | cut -d'"' -f2)
|
||||
|
||||
typst_assets_rev=$(grep 'typst-assets.*git' Cargo.toml | grep 'rev = ' | cut -d'"' -f4)
|
||||
|
||||
echo "typst_version=$typst_version" >> $GITHUB_ENV
|
||||
echo "typst_assets_rev=$typst_assets_rev" >> $GITHUB_ENV
|
||||
|
||||
# Get base commit
|
||||
git remote add upstream https://github.com/typst/typst.git && git fetch upstream main --prune
|
||||
typst_base_commit=$(git merge-base HEAD upstream/main 2>/dev/null)
|
||||
typst_base_msg=$(git --no-pager log --format="%s" -1 $base_sha)
|
||||
echo "typst_base_commit=$typst_base_commit" >> $GITHUB_ENV
|
||||
echo "typst_base_msg=$typst_base_msg" >> $GITHUB_ENV
|
||||
|
||||
- name: Update typst dependencies in tinymist
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \
|
||||
"$typst_version" \
|
||||
"$typst_assets_rev"
|
||||
|
||||
revs_json=$(cat <<EOF
|
||||
{
|
||||
"typst": "${latest_typst_rev}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-patch-revs "$revs_json"
|
||||
|
||||
- name: Update world crates version
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . bump-world-crates "$new_version"
|
||||
|
||||
cargo update -p tinymist-derive -p tinymist-l10n -p tinymist-package -p tinymist-std -p tinymist-vfs -p tinymist-world -p tinymist-project -p tinymist-task -p typst-shim
|
||||
git add -A
|
||||
git commit -m "build: bump world crates to $new_version"
|
||||
git push origin nightly
|
||||
|
||||
world_commit=$(git rev-parse HEAD)
|
||||
echo "world_commit=$world_commit" >> $GITHUB_ENV
|
||||
|
||||
- name: Update typst.ts
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
# Clone typst.ts
|
||||
git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typst.ts.git /tmp/typst.ts
|
||||
cd /tmp/typst.ts
|
||||
git checkout nightly
|
||||
|
||||
new_version="$new_version"
|
||||
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-world-crates "$new_version"
|
||||
|
||||
# Update typst dependencies
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \
|
||||
"$typst_version" \
|
||||
"$typst_assets_rev"
|
||||
|
||||
# Update patches
|
||||
revs_json=$(cat <<EOF
|
||||
{
|
||||
"tinymist": "${world_commit}",
|
||||
"typst": "${latest_typst_rev}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-patch-revs "$revs_json"
|
||||
|
||||
cargo update
|
||||
git add -A
|
||||
git commit -m "build: update tinymist and typst"
|
||||
git push origin nightly
|
||||
|
||||
reflexo_commit=$(git rev-parse HEAD)
|
||||
echo "reflexo_commit=$reflexo_commit" >> $GITHUB_ENV
|
||||
|
||||
- name: Update typstyle
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
# Clone typstyle
|
||||
git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typstyle.git /tmp/typstyle
|
||||
cd /tmp/typstyle
|
||||
git checkout nightly
|
||||
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-world-crates "$new_version"
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \
|
||||
"$typst_version" \
|
||||
"$typst_assets_rev"
|
||||
|
||||
# Update patches
|
||||
revs_json=$(cat <<EOF
|
||||
{
|
||||
"tinymist": "${world_commit}",
|
||||
"typst": "${latest_typst_rev}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-patch-revs "$revs_json"
|
||||
|
||||
cargo update
|
||||
git add -A
|
||||
git commit -m "build: update tinymist to ${new_version}"
|
||||
git push origin nightly
|
||||
|
||||
typstyle_commit=$(git rev-parse HEAD)
|
||||
echo "typstyle_commit=$typstyle_commit" >> $GITHUB_ENV
|
||||
|
||||
- name: Update typst-ansi-hl
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
# Clone typst-ansi-hl
|
||||
git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typst-ansi-hl.git /tmp/typst-ansi-hl
|
||||
cd /tmp/typst-ansi-hl
|
||||
git checkout nightly
|
||||
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \
|
||||
"$typst_version" \
|
||||
"$typst_assets_rev"
|
||||
|
||||
# Update patches
|
||||
revs_json=$(cat <<EOF
|
||||
{
|
||||
"typst": "${latest_typst_rev}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-patch-revs "$revs_json"
|
||||
|
||||
cargo update
|
||||
git add -A
|
||||
git commit -m "build: update typst-syntax" || true
|
||||
git push origin nightly
|
||||
|
||||
hl_commit=$(git rev-parse HEAD)
|
||||
echo "hl_commit=$hl_commit" >> $GITHUB_ENV
|
||||
|
||||
- name: Update tinymist patches and versions
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
# Update patch revisions using script
|
||||
revs_json=$(cat <<EOF
|
||||
{
|
||||
"reflexo": "${reflexo_commit}",
|
||||
"typst-ansi-hl": "${hl_commit}",
|
||||
"typstyle": "${typstyle_commit}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-patch-revs "$revs_json"
|
||||
|
||||
# Update main version
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-main-version "$new_version"
|
||||
|
||||
- name: Update version files
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-version-files "$new_version"
|
||||
|
||||
- name: Generate changelog
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
tinymist_base_commit=$(git merge-base HEAD origin/main)
|
||||
tinymist_base_msg=$(git --no-pager log --format="%s" -1 $base_sha)
|
||||
|
||||
node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . generate-changelog \
|
||||
"$new_version" \
|
||||
"$tinymist_base_commit" \
|
||||
"$tinymist_base_msg" \
|
||||
"$latest_typst_rev" \
|
||||
"$typst_base_commit" \
|
||||
"$typst_base_msg"
|
||||
|
||||
- name: Final commit and tag
|
||||
if: steps.check_updates.outputs.need_release == 'true'
|
||||
run: |
|
||||
new_version="$new_version"
|
||||
|
||||
cargo update
|
||||
git add -A
|
||||
git commit -m "build: bump version to ${new_version}"
|
||||
|
||||
git tag "v${new_version}"
|
||||
git push origin nightly
|
||||
git push origin "v${new_version}"
|
||||
|
||||
echo "Successfully released tinymist ${new_version}!"
|
||||
|
||||
- name: No updates needed
|
||||
if: steps.check_updates.outputs.need_release != 'true'
|
||||
run: |
|
||||
echo "No updates needed. All dependencies are up to date."
|
||||
|
|
@ -44,14 +44,15 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@rainbowatcher/toml-edit-js": "^0.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
||||
"@typescript-eslint/parser": "^8.24.1",
|
||||
"cpr": "^3.0.1",
|
||||
"eslint": "^9.20.1",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-n": "^17.15.1",
|
||||
"eslint-plugin-promise": "^7.2.1",
|
||||
"cpr": "^3.0.1",
|
||||
"prettier": "^3.0.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"typescript": "^5.3.3",
|
||||
|
|
|
|||
600
scripts/nightly-utils.mjs
Normal file
600
scripts/nightly-utils.mjs
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import init, { edit, parse, stringify } from "@rainbowatcher/toml-edit-js";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const ROOT_DIR = path.dirname(__dirname);
|
||||
|
||||
class NightlyUtils {
|
||||
constructor(rootDir = ROOT_DIR) {
|
||||
this.rootDir = rootDir;
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
async ensureInit() {
|
||||
if (!this.initialized) {
|
||||
await init();
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
async readToml(filePath) {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
return { content, parsed: parse(content) };
|
||||
}
|
||||
|
||||
async writeToml(filePath, content) {
|
||||
await fs.writeFile(filePath, content);
|
||||
}
|
||||
|
||||
async readJson(filePath) {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
return JSON.parse(content);
|
||||
}
|
||||
|
||||
async writeJson(filePath, data) {
|
||||
const content = JSON.stringify(data, null, 2) + '\n';
|
||||
await fs.writeFile(filePath, content);
|
||||
}
|
||||
|
||||
async getCurrentDependencyRevs() {
|
||||
await this.ensureInit();
|
||||
const cargoTomlPath = path.join(this.rootDir, 'Cargo.toml');
|
||||
const { parsed } = await this.readToml(cargoTomlPath);
|
||||
|
||||
const patches = parsed?.patch?.['crates-io'] || {};
|
||||
|
||||
const extractRev = (depInfo) => {
|
||||
if (typeof depInfo === 'string') return null;
|
||||
if (typeof depInfo === 'object' && depInfo.rev) return depInfo.rev;
|
||||
return null;
|
||||
};
|
||||
|
||||
return {
|
||||
typst: extractRev(patches.typst),
|
||||
reflexo: extractRev(patches.reflexo),
|
||||
typstyle: extractRev(patches['typstyle-core']),
|
||||
'typst-ansi-hl': extractRev(patches['typst-ansi-hl'])
|
||||
};
|
||||
}
|
||||
|
||||
async updateDependencies(crates, version) {
|
||||
await this.ensureInit();
|
||||
const cargoTomlPath = path.join(this.rootDir, 'Cargo.toml');
|
||||
const { content } = await this.readToml(cargoTomlPath);
|
||||
|
||||
let updatedContent = content;
|
||||
|
||||
const updateCrateDependencyVersion = (content, crate, newVersion) => {
|
||||
const parsed = parse(content)
|
||||
const deps = parsed?.workspace?.dependencies || {};
|
||||
|
||||
if (!(crate in deps)) {
|
||||
throw Error("Missing package")
|
||||
}
|
||||
|
||||
const crateDepInfo = deps[crate];
|
||||
|
||||
if (typeof crateDepInfo === 'string') {
|
||||
return edit(content, `workspace.dependencies.${crate}`, newVersion)
|
||||
}
|
||||
if (typeof crateDepInfo === 'object' && crateDepInfo.version) {
|
||||
return edit(content, `workspace.dependencies.${crate}.version`, newVersion)
|
||||
}
|
||||
|
||||
throw Error("Invalid dependency info")
|
||||
}
|
||||
|
||||
for (const crate of crates) {
|
||||
try {
|
||||
updatedContent = updateCrateDependencyVersion(updatedContent, crate, version)
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
await this.writeToml(cargoTomlPath, updatedContent);
|
||||
}
|
||||
|
||||
async updateTypstDependencies(typstVersion, typstAssetsRev) {
|
||||
await this.ensureInit();
|
||||
|
||||
const typstCrates = [
|
||||
'typst-cli',
|
||||
'typst-eval',
|
||||
'typst-html',
|
||||
'typst-ide',
|
||||
'typst-kit',
|
||||
'typst-layout',
|
||||
'typst-library',
|
||||
'typst-macros',
|
||||
'typst-pdf',
|
||||
'typst-realize',
|
||||
'typst-render',
|
||||
'typst-svg',
|
||||
'typst-syntax',
|
||||
'typst-timing',
|
||||
'typst-utils',
|
||||
'typst',
|
||||
];
|
||||
await this.updateDependencies(typstCrates, typstVersion)
|
||||
|
||||
const cargoTomlPath = path.join(this.rootDir, 'Cargo.toml');
|
||||
const { content } = await this.readToml(cargoTomlPath);
|
||||
|
||||
let updatedContent = content;
|
||||
|
||||
try {
|
||||
updatedContent = edit(updatedContent, 'workspace.dependencies.typst-assets.rev', typstAssetsRev);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update typst - assets rev: ${e.message} `);
|
||||
}
|
||||
|
||||
await this.writeToml(cargoTomlPath, updatedContent);
|
||||
}
|
||||
|
||||
async bumpWorldCrates(newVersion, bump = false) {
|
||||
await this.ensureInit();
|
||||
|
||||
const worldCrates = [
|
||||
'tinymist-derive', 'tinymist-l10n', 'tinymist-package', 'tinymist-std',
|
||||
'tinymist-vfs', 'tinymist-world', 'tinymist-project', 'tinymist-task', 'typst-shim'
|
||||
];
|
||||
await this.updateDependencies(worldCrates, newVersion);
|
||||
|
||||
if (!bump) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const crate of worldCrates) {
|
||||
const cratePath = path.join(this.rootDir, 'crates', crate, 'Cargo.toml');
|
||||
try {
|
||||
const { content: crateContent } = await this.readToml(cratePath);
|
||||
const updatedCrateContent = edit(crateContent, 'package.version', newVersion);
|
||||
await this.writeToml(cratePath, updatedCrateContent);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update ${crate}/Cargo.toml: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updatePatchRevs(revs) {
|
||||
await this.ensureInit();
|
||||
const cargoTomlPath = path.join(this.rootDir, 'Cargo.toml');
|
||||
const { content, parsed } = await this.readToml(cargoTomlPath);
|
||||
|
||||
let updatedContent = content;
|
||||
|
||||
const patchMappings = [
|
||||
{ key: 'reflexo', patches: ['reflexo', 'reflexo-typst', 'reflexo-vec2svg'] },
|
||||
{ key: 'typst-ansi-hl', patches: ['typst-ansi-hl'] },
|
||||
{ key: 'typstyle', patches: ['typstyle-core'] },
|
||||
{
|
||||
key: 'typst', patches: [
|
||||
'typst-cli',
|
||||
'typst-eval',
|
||||
'typst-html',
|
||||
'typst-ide',
|
||||
'typst-kit',
|
||||
'typst-layout',
|
||||
'typst-library',
|
||||
'typst-macros',
|
||||
'typst-pdf',
|
||||
'typst-realize',
|
||||
'typst-render',
|
||||
'typst-svg',
|
||||
'typst-syntax',
|
||||
'typst-timing',
|
||||
'typst-utils',
|
||||
'typst',
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'tinymist', patches: [
|
||||
'crityp',
|
||||
'tinymist',
|
||||
'tinymist-assets',
|
||||
'tinymist-dap',
|
||||
'tinymist-derive',
|
||||
'tinymist-lint',
|
||||
'tinymist-project',
|
||||
'tinymist-render',
|
||||
'tinymist-task',
|
||||
'tinymist-vfs',
|
||||
'typlite',
|
||||
'typst-shim',
|
||||
'sync-lsp',
|
||||
'tinymist-analysis',
|
||||
'tinymist-core',
|
||||
'tinymist-debug',
|
||||
'tinymist-l10n',
|
||||
'tinymist-package',
|
||||
'tinymist-query',
|
||||
'tinymist-std',
|
||||
'tinymist-tests',
|
||||
'tinymist-world',
|
||||
'typst-preview',
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
for (const mapping of patchMappings) {
|
||||
if (revs[mapping.key]) {
|
||||
for (const patchName of mapping.patches) {
|
||||
try {
|
||||
let patchInfo = parsed?.patch?.['crates-io'][patchName] || null
|
||||
if (!patchInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete patchInfo.branch;
|
||||
delete patchInfo.tag;
|
||||
|
||||
patchInfo.rev = revs[mapping.key];
|
||||
updatedContent = edit(updatedContent, `patch.crates-io.${patchName}`, patchInfo);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update ${patchName} rev: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.writeToml(cargoTomlPath, updatedContent);
|
||||
}
|
||||
|
||||
async updateMainVersion(newVersion) {
|
||||
await this.ensureInit();
|
||||
|
||||
const nonWorldCrates = [
|
||||
'sync-ls', 'tinymist', 'tinymist-analysis', 'tinymist-core', 'tinymist-debug',
|
||||
'tinymist-lint', 'tinymist-query', 'tinymist-render', 'tinymist-preview', 'typlite'
|
||||
];
|
||||
await this.updateDependencies(nonWorldCrates, newVersion);
|
||||
|
||||
const cargoTomlPath = path.join(this.rootDir, 'Cargo.toml');
|
||||
const { content } = await this.readToml(cargoTomlPath);
|
||||
|
||||
let updatedContent = edit(content, 'workspace.package.version', newVersion);
|
||||
|
||||
await this.writeToml(cargoTomlPath, updatedContent);
|
||||
}
|
||||
|
||||
async updateVersionFiles(newVersion) {
|
||||
const jsonFiles = [
|
||||
'contrib/html/editors/vscode/package.json',
|
||||
'crates/tinymist-core/package.json',
|
||||
'editors/vscode/package.json',
|
||||
'syntaxes/textmate/package.json'
|
||||
];
|
||||
|
||||
for (const file of jsonFiles) {
|
||||
const filePath = path.join(this.rootDir, file);
|
||||
try {
|
||||
const json = await this.readJson(filePath);
|
||||
json.version = newVersion;
|
||||
await this.writeJson(filePath, json);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update ${file}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
await this.updateSpecialFiles(newVersion);
|
||||
}
|
||||
|
||||
async updateSpecialFiles(newVersion) {
|
||||
// Nix flake
|
||||
try {
|
||||
const nixFlakePath = path.join(this.rootDir, 'contrib/nix/dev/flake.nix');
|
||||
let nixContent = await fs.readFile(nixFlakePath, 'utf-8');
|
||||
nixContent = nixContent.replace(
|
||||
/version = "[^"]*";/g,
|
||||
`version = "${newVersion}";`
|
||||
);
|
||||
await fs.writeFile(nixFlakePath, nixContent);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update flake.nix: ${e.message}`);
|
||||
}
|
||||
|
||||
// Dockerfile
|
||||
try {
|
||||
const dockerfilePath = path.join(this.rootDir, 'editors/neovim/samples/lazyvim-dev/Dockerfile');
|
||||
let dockerContent = await fs.readFile(dockerfilePath, 'utf-8');
|
||||
dockerContent = dockerContent.replace(
|
||||
/FROM myriaddreamin\/tinymist:[^ ]* as tinymist/g,
|
||||
`FROM myriaddreamin/tinymist:${newVersion} as tinymist`
|
||||
);
|
||||
await fs.writeFile(dockerfilePath, dockerContent);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update Dockerfile: ${e.message}`);
|
||||
}
|
||||
|
||||
// bootstrap.sh
|
||||
try {
|
||||
const bootstrapPath = path.join(this.rootDir, 'editors/neovim/bootstrap.sh');
|
||||
let bootstrapContent = await fs.readFile(bootstrapPath, 'utf-8');
|
||||
bootstrapContent = bootstrapContent.replace(
|
||||
/myriaddreamin\/tinymist:[^ ]*/g,
|
||||
`myriaddreamin/tinymist:${newVersion}`
|
||||
);
|
||||
bootstrapContent = bootstrapContent.replace(
|
||||
/myriaddreamin\/tinymist-nvim:[^ ]*/g,
|
||||
`myriaddreamin/tinymist-nvim:${newVersion}`
|
||||
);
|
||||
await fs.writeFile(bootstrapPath, bootstrapContent);
|
||||
} catch (e) {
|
||||
console.warn(`Warning: Could not update bootstrap.sh: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async generateChangelog(newVersion, tinymistBaseCommit, tinymistBaseMessage, typstRev, typstBaseCommit, typstBaseMessage) {
|
||||
const currentDate = new Date().toISOString().split('T')[0];
|
||||
const changelogPath = path.join(this.rootDir, 'editors/vscode/CHANGELOG.md');
|
||||
|
||||
// Template for the new changelog entry.
|
||||
const newChangelogEntryTemplate = `## v${newVersion} - [${currentDate}]
|
||||
|
||||
Nightly Release at [${tinymistBaseMessage}](https://github.com/Myriad-Dreamin/tinymist/commit/${tinymistBaseCommit}), using [ParaN3xus/typst rev ${typstRev.slice(0, 7)}](https://github.com/ParaN3xus/typst/commit/${typstRev}), a.k.a. [typst/typst ${typstBaseMessage}](https://github.com/typst/typst/commit/${typstBaseCommit}).
|
||||
|
||||
**Full Changelog**: https://github.com/Myriad-Dreamin/tinymist/compare/{{PREV_VERSION}}...v${newVersion}
|
||||
`;
|
||||
|
||||
try {
|
||||
const content = await fs.readFile(changelogPath, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
const newVersionBase = `v${newVersion.split('-')[0]}`;
|
||||
|
||||
const filteredLines = [];
|
||||
let isSkipping = false;
|
||||
|
||||
// skip lines with same base ver
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('## v')) {
|
||||
const match = line.match(/## (v[0-9]+\.[0-9]+\.[0-9]+)/);
|
||||
if (match && match[1] === newVersionBase) {
|
||||
isSkipping = true;
|
||||
} else {
|
||||
isSkipping = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSkipping) {
|
||||
filteredLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
// find insert point
|
||||
let previousVersion = '';
|
||||
for (const line of filteredLines) {
|
||||
if (line.startsWith('## v')) {
|
||||
const match = line.match(/## (v[0-9][^\s]*)/);
|
||||
if (match) {
|
||||
previousVersion = match[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let finalEntry = newChangelogEntryTemplate.replace(
|
||||
'{{PREV_VERSION}}',
|
||||
previousVersion || 'HEAD~1'
|
||||
);
|
||||
|
||||
const firstReleaseIndex = filteredLines.findIndex(line => line.startsWith('## v'));
|
||||
|
||||
let finalContent;
|
||||
if (firstReleaseIndex >= 0) {
|
||||
const newLines = [
|
||||
...filteredLines.slice(0, firstReleaseIndex),
|
||||
finalEntry,
|
||||
...filteredLines.slice(firstReleaseIndex)
|
||||
];
|
||||
finalContent = newLines.join('\n');
|
||||
} else {
|
||||
// append
|
||||
finalContent = filteredLines.join('\n').trim() + '\n\n' + finalEntry;
|
||||
}
|
||||
|
||||
await fs.writeFile(changelogPath, finalContent.trim() + '\n');
|
||||
|
||||
} catch (e) {
|
||||
// create
|
||||
console.warn(`Warning: Could not update CHANGELOG.md: ${e.message}. Creating a new one.`);
|
||||
const finalEntry = newChangelogEntryTemplate.replace('{{PREV_VERSION}}', 'HEAD~1');
|
||||
await fs.writeFile(changelogPath, finalEntry);
|
||||
}
|
||||
}
|
||||
|
||||
calculateNewVersion(currentVersion, releaseType) {
|
||||
const validVersionRegex = /^[0-9.\-rc]+$/;
|
||||
if (!validVersionRegex.test(currentVersion)) {
|
||||
throw new Error(`Invalid version format: ${currentVersion}. Version can only contain numbers, dots, hyphens, and 'rc'.`);
|
||||
}
|
||||
|
||||
if (releaseType === 'canary') {
|
||||
const [baseVersion, suffix] = currentVersion.split('-');
|
||||
const versionParts = baseVersion.split('.');
|
||||
const currentPatch = parseInt(versionParts[2]);
|
||||
|
||||
if (currentPatch % 2 === 0) {
|
||||
// even -> +1-rc1
|
||||
const newPatch = currentPatch + 1;
|
||||
const newVersion = `${versionParts[0]}.${versionParts[1]}.${newPatch}`;
|
||||
return `${newVersion}-rc1`;
|
||||
} else {
|
||||
// odd
|
||||
if (suffix && suffix.startsWith('rc')) {
|
||||
const rcNumber = parseInt(suffix.replace('rc', ''));
|
||||
|
||||
if (rcNumber === 9) {
|
||||
// rc9 -> +1-rc1
|
||||
const newPatch = currentPatch + 2;
|
||||
const newVersion = `${versionParts[0]}.${versionParts[1]}.${newPatch}`;
|
||||
return `${newVersion}-rc1`;
|
||||
} else {
|
||||
// rc -> rc+1
|
||||
const newRcNumber = rcNumber + 1;
|
||||
return `${baseVersion}-rc${newRcNumber}`;
|
||||
}
|
||||
} else {
|
||||
// no rc -> +2-rc1
|
||||
const newPatch = currentPatch + 2;
|
||||
const newVersion = `${versionParts[0]}.${versionParts[1]}.${newPatch}`;
|
||||
return `${newVersion}-rc1`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// nightly release
|
||||
// simply remove -rc
|
||||
const baseVersion = currentVersion.split('-')[0];
|
||||
const versionParts = baseVersion.split('.');
|
||||
const currentPatch = parseInt(versionParts[2]);
|
||||
|
||||
if (currentPatch % 2 === 0) {
|
||||
throw new Error(`Current patch version ${currentPatch} is not odd. Nightly releases require odd patch versions.`);
|
||||
}
|
||||
|
||||
return baseVersion;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const rootDir = process.argv[2];
|
||||
|
||||
const utils = new NightlyUtils(rootDir);
|
||||
|
||||
const command = process.argv[3];
|
||||
|
||||
if (!command) {
|
||||
console.error('Please specify a command');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (command) {
|
||||
case 'get-current-revs': {
|
||||
const revs = await utils.getCurrentDependencyRevs();
|
||||
Object.entries(revs).forEach(([key, value]) => {
|
||||
console.log(`current_${key.replaceAll('-', '_')}_rev=${value || ''}`);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'update-typst-deps': {
|
||||
const typstVersion = process.argv[4];
|
||||
const assetsRev = process.argv[5];
|
||||
if (!typstVersion || !assetsRev) {
|
||||
throw new Error('Usage: update-typst-deps <typst-version> <assets-rev>');
|
||||
}
|
||||
await utils.updateTypstDependencies(typstVersion, assetsRev);
|
||||
console.log(`Updated typst dependencies to ${typstVersion}`);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'update-world-crates': {
|
||||
const newVersion = process.argv[4];
|
||||
if (!newVersion) {
|
||||
throw new Error('Usage: update-world-crates <new-version>');
|
||||
}
|
||||
await utils.bumpWorldCrates(newVersion, false);
|
||||
console.log(`Updated world crates to ${newVersion}`);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'bump-world-crates': {
|
||||
const newVersion = process.argv[4];
|
||||
if (!newVersion) {
|
||||
throw new Error('Usage: bump-world-crates <new-version>');
|
||||
}
|
||||
await utils.bumpWorldCrates(newVersion, true);
|
||||
console.log(`Updated world crates to ${newVersion}`);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'update-patch-revs': {
|
||||
const revsJson = process.argv[4];
|
||||
if (!revsJson) {
|
||||
throw new Error('Usage: update-patch-revs <revs-json>');
|
||||
}
|
||||
const revs = JSON.parse(revsJson);
|
||||
await utils.updatePatchRevs(revs);
|
||||
console.log('Updated patch revisions');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'update-main-version': {
|
||||
const newVersion = process.argv[4];
|
||||
if (!newVersion) {
|
||||
throw new Error('Usage: update-main-version <new-version>');
|
||||
}
|
||||
await utils.updateMainVersion(newVersion);
|
||||
console.log(`Updated main version to ${newVersion}`);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'update-version-files': {
|
||||
const newVersion = process.argv[4];
|
||||
if (!newVersion) {
|
||||
throw new Error('Usage: update-version-files <new-version>');
|
||||
}
|
||||
await utils.updateVersionFiles(newVersion);
|
||||
console.log(`Updated version files to ${newVersion}`);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'generate-changelog': {
|
||||
const newVersion = process.argv[4];
|
||||
const tinymistBaseCommit = process.argv[5];
|
||||
const tinymistBaseMessage = process.argv[6];
|
||||
const typstRev = process.argv[7];
|
||||
const typstBaseCommit = process.argv[8];
|
||||
const typstBaseMessage = process.argv[9];
|
||||
if (!newVersion || !tinymistBaseCommit || !tinymistBaseMessage || !typstRev || !typstBaseCommit || !typstBaseMessage) {
|
||||
throw new Error('Usage: generate-changelog <version> <tinymist-base-commit> <tinymist-base-message> <typst-rev> <typst-base-commit> <typst-base-message>');
|
||||
}
|
||||
await utils.generateChangelog(newVersion, tinymistBaseCommit, tinymistBaseMessage, typstRev, typstBaseCommit, typstBaseMessage);
|
||||
console.log('Generated changelog');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'calculate-version': {
|
||||
const currentVersion = process.argv[4];
|
||||
const releaseType = process.argv[5];
|
||||
if (!currentVersion || !releaseType) {
|
||||
throw new Error('Usage: calculate-version <current-version> <release-type>');
|
||||
}
|
||||
const newVersion = utils.calculateNewVersion(currentVersion, releaseType);
|
||||
console.log(newVersion);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.error(`Unknown command: ${command}`);
|
||||
console.error('Available commands:');
|
||||
console.error(' get-current-revs');
|
||||
console.error(' update-typst-deps <typst-version> <assets-rev>');
|
||||
console.error(' bump-world-crates <new-version>');
|
||||
console.error(' update-world-crates <new-version>');
|
||||
console.error(' update-patch-revs <revs-json>');
|
||||
console.error(' update-main-version <new-version>');
|
||||
console.error(' update-version-files <new-version>');
|
||||
console.error(' generate-changelog <version> <tinymist-base-commit> <tinymist-base-message> <typst-rev> <typst-base-commit> <typst-base-message>');
|
||||
console.error(' calculate-version <current-version> <release-type>');
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
main();
|
||||
}
|
||||
|
||||
export default NightlyUtils;
|
||||
|
|
@ -449,6 +449,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@rainbowatcher/toml-edit-js@^0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@rainbowatcher/toml-edit-js/-/toml-edit-js-0.5.1.tgz#1c205eede4f9ac7b955402b755126ebe60c83509"
|
||||
integrity sha512-9Q7CGm24nvJyDy4STQvrPrA09U7zgLJ7GaLHBiJhA8vVoRjmfsCG9R0PjJtzytU4FUD2FiZvBlN5KCTOux/gFQ==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.34.8":
|
||||
version "4.34.8"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz#731df27dfdb77189547bcef96ada7bf166bbb2fb"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue