mirror of
https://github.com/mengxi-ream/read-frog.git
synced 2026-08-30 17:48:58 +08:00
chore: add github stuff
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
||||
"changelog": [
|
||||
"@changesets/changelog-github",
|
||||
{
|
||||
"repo": "mengxi-ream/read-frog"
|
||||
}
|
||||
],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "restricted",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": [],
|
||||
"privatePackages": {
|
||||
"version": true,
|
||||
"tag": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: mengxi-ream
|
||||
@@ -0,0 +1,85 @@
|
||||
name: Report a bug
|
||||
description: Create a report to help us improve Read Frog
|
||||
labels: [bug]
|
||||
title: '[BUG] '
|
||||
assignees: []
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: preflight
|
||||
attributes:
|
||||
label: Before you report
|
||||
description: |
|
||||
Please confirm the following before submitting. For questions and quick help, join our Discord community.
|
||||
Discord: https://discord.gg/ej45e3PezJ
|
||||
options:
|
||||
- label: I have searched existing issues to avoid duplicates
|
||||
required: true
|
||||
- label: I have tried with the latest available version (or can reproduce on latest)
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template is used for reporting an issue with Read Frog.
|
||||
|
||||
Feature requests should be opened via the [Feature Request Form](https://github.com/mengxi-ream/read-frog/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.yml&title=)
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Current vs. Expected behavior
|
||||
description: |
|
||||
A clear and concise description of what happened (e.g., screenshots, logs, errors) and what you expected to happen.
|
||||
|
||||
Skipping this / failure to provide complete information may result in the issue being closed.
|
||||
placeholder: 'Following the steps from the previous section, I expected A to happen, but I observed B instead.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: |
|
||||
A step-by-step description of how to reproduce the issue. Screenshots can be provided in the issue body as well.
|
||||
placeholder: |
|
||||
Ex:
|
||||
1. Open a news article page
|
||||
2. Click the Read Frog icon to open the popup
|
||||
3. Enable Immersive Translation
|
||||
4. Observe translation not appearing on the page
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: areas
|
||||
attributes:
|
||||
label: Which area(s) are affected? (Select all that apply)
|
||||
multiple: true
|
||||
options:
|
||||
- Browser Extension
|
||||
- Website
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: extension_version
|
||||
attributes:
|
||||
label: Extension version (if applicable)
|
||||
description: Provide the current version of the browser extension
|
||||
placeholder: 1.x.x
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Provide environment information
|
||||
description: Please collect the following information and paste the results.
|
||||
render: bash
|
||||
placeholder: |
|
||||
- OS: [e.g. macOS 14.5]
|
||||
- Browser: [e.g. Chrome 126, Edge 125]
|
||||
- Extension channel/version: [e.g. Chrome Web Store 1.2.3]
|
||||
- Website: [e.g. https://readfrog.app, date/time observed]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: |
|
||||
Any extra information that might help us investigate. For example, is it only reproducible online, or locally too? Is the issue only happening in a specific website or browser?
|
||||
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Read Frog Discord
|
||||
url: https://discord.gg/ej45e3PezJ
|
||||
about: Quick questions or support are often answered faster in Discord.
|
||||
- name: Official Website
|
||||
url: https://readfrog.app
|
||||
about: Learn more about Read Frog and access docs and resources.
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for Read Frog
|
||||
title: '[FEATURE] '
|
||||
labels: [enhancement]
|
||||
assignees: []
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: preflight
|
||||
attributes:
|
||||
label: Before you begin
|
||||
description: |
|
||||
Please confirm the following before submitting. For questions and quick help, join our Discord community.
|
||||
Discord: https://discord.gg/ej45e3PezJ
|
||||
options:
|
||||
- label: I have searched existing issues to avoid duplicates
|
||||
required: true
|
||||
- label: I am willing to contribute a PR for this feature
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template is used for suggesting a feature for Read Frog.
|
||||
|
||||
Bug reports should be opened via the [Bug Report Form](https://github.com/mengxi-ream/read-frog/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=)
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: areas
|
||||
attributes:
|
||||
label: Which area(s) would this feature affect? (Select all that apply)
|
||||
multiple: true
|
||||
options:
|
||||
- Browser Extension
|
||||
- Website
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,52 @@
|
||||
## Type of Changes
|
||||
|
||||
<!--- Please select one type below -->
|
||||
|
||||
- [ ] ✨ New feature (feat)
|
||||
- [ ] 🐛 Bug fix (fix)
|
||||
- [ ] 📝 Documentation change (docs)
|
||||
- [ ] 💄 UI/style change (style)
|
||||
- [ ] ♻️ Code refactoring (refactor)
|
||||
- [ ] ⚡ Performance improvement (perf)
|
||||
- [ ] ✅ Test related (test)
|
||||
- [ ] 🔧 Build or dependencies update (build)
|
||||
- [ ] 🔄 CI/CD related (ci)
|
||||
- [ ] 🌐 Internationalization (i18n)
|
||||
- [ ] 🧠 AI model related (ai)
|
||||
- [ ] 🔄 Revert a previous commit (revert)
|
||||
- [ ] 📦 Other changes that do not modify src or test files (chore)
|
||||
|
||||
## Description
|
||||
|
||||
<!--- Please describe the changes in the PR and the problem it solves -->
|
||||
|
||||
## Related Issue
|
||||
|
||||
<!--- If this PR closes an issue, please link the issue below -->
|
||||
|
||||
Closes #
|
||||
|
||||
## How Has This Been Tested?
|
||||
|
||||
<!--- Please describe how you tested your changes -->
|
||||
|
||||
- [ ] Added unit tests
|
||||
- [ ] Verified through manual testing
|
||||
|
||||
## Screenshots
|
||||
|
||||
<!--- If applicable, add screenshots to help explain your changes -->
|
||||
|
||||
## Checklist
|
||||
|
||||
<!--- Go over all the following points before requesting a review -->
|
||||
|
||||
- [ ] I have tested these changes locally
|
||||
- [ ] I have updated the documentation accordingly if necessary
|
||||
- [ ] My code follows the code style of this project
|
||||
- [ ] My changes do not break existing functionality
|
||||
- [ ] If my code was generated by AI, I have proofread and improved it as necessary.
|
||||
|
||||
## Additional Information
|
||||
|
||||
<!--- Any other information that reviewers should know -->
|
||||
@@ -0,0 +1,45 @@
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- ignore-for-release
|
||||
- dependencies
|
||||
- automated
|
||||
- bot
|
||||
- github-actions
|
||||
authors:
|
||||
- dependabot[bot]
|
||||
- github-actions[bot]
|
||||
- github-actions
|
||||
- action-bot
|
||||
|
||||
categories:
|
||||
- title: 🚨 Breaking Changes
|
||||
labels:
|
||||
- breaking-change
|
||||
- title: ✨ New Features
|
||||
labels:
|
||||
- feat
|
||||
- title: 🐛 Bug Fixes
|
||||
labels:
|
||||
- fix
|
||||
- title: 🤖 AI
|
||||
labels:
|
||||
- ai
|
||||
- title: 🎨 UI Styles
|
||||
labels:
|
||||
- style
|
||||
- title: 🚀 Performance
|
||||
labels:
|
||||
- perf
|
||||
- title: 📚 Documentation
|
||||
labels:
|
||||
- docs
|
||||
- title: 🔧 Maintenance
|
||||
labels:
|
||||
- chore
|
||||
- refactor
|
||||
- ci
|
||||
- build
|
||||
- i18n
|
||||
- title: Other Changes
|
||||
labels: ['*']
|
||||
@@ -0,0 +1,176 @@
|
||||
name: PR - Major Version Warning
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths:
|
||||
- '.changeset/*.md'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
check-major:
|
||||
name: Check Breaking Changes
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get changed changeset files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files: '.changeset/*.md'
|
||||
files_ignore: .changeset/README.md
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Check for major changes
|
||||
id: check-major
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
echo "Checking changeset files for major changes..."
|
||||
|
||||
major_files=""
|
||||
major_packages=""
|
||||
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
echo "Checking file: $file"
|
||||
|
||||
# Extract front matter and check for major (more robust parsing)
|
||||
if sed -n '/^---$/,/^---$/p' "$file" | grep -q ": major"; then
|
||||
echo "Found major change in: $file"
|
||||
major_files="$major_files$file "
|
||||
|
||||
# Extract package names with major changes (more precise)
|
||||
packages=$(sed -n '/^---$/,/^---$/p' "$file" | grep ": major" | sed 's/^"\([^"]*\)": major$/\1/' | tr '\n' ' ')
|
||||
major_packages="$major_packages$packages"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$major_files" ]; then
|
||||
echo "has_major=true" >> $GITHUB_OUTPUT
|
||||
echo "major_files=$major_files" >> $GITHUB_OUTPUT
|
||||
echo "major_packages=$major_packages" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_major=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Comment on PR with major version warning
|
||||
if: steps.check-major.outputs.has_major == 'true' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const majorFiles = ${{ toJSON(steps.check-major.outputs.major_files) }}.trim();
|
||||
const majorPackages = ${{ toJSON(steps.check-major.outputs.major_packages) }}.trim();
|
||||
|
||||
// Check if we already have a major version warning comment
|
||||
const comments = await github.rest.issues.listComments({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
const botComment = comments.data.find(comment =>
|
||||
comment.user.type === 'Bot' &&
|
||||
comment.body.includes('⚠️ Major Version Change Detected')
|
||||
);
|
||||
|
||||
const comment = `## ⚠️ Major Version Change Detected
|
||||
|
||||
This PR contains **MAJOR** version changes, which means **breaking changes**!
|
||||
|
||||
### 📦 Affected Packages
|
||||
${majorPackages.split(' ').filter(p => p).map(pkg => `- \`${pkg}\``).join('\n')}
|
||||
|
||||
### 📁 Related Changeset Files
|
||||
${majorFiles.split(' ').filter(f => f).map(file => `- \`${file}\``).join('\n')}
|
||||
|
||||
### 🔢 Version Impact
|
||||
|
||||
Major version changes will:
|
||||
- Increment the major version number by 1 (e.g., 1.2.3 → 2.0.0)
|
||||
- Reset minor and patch versions to 0
|
||||
- Indicate **breaking changes** that may cause existing user code to fail
|
||||
|
||||
### ❓ Please Confirm
|
||||
|
||||
Please carefully confirm the following:
|
||||
|
||||
1. **Does this really contain breaking changes?**
|
||||
- API removal or modification
|
||||
- Default behavior changes
|
||||
- Major dependency updates
|
||||
|
||||
2. **Should you use \`minor\` or \`patch\` instead?**
|
||||
- \`minor\`: New features but backward compatible
|
||||
- \`patch\`: Bug fixes, backward compatible
|
||||
|
||||
3. **Are you ready to release a major version?**
|
||||
- Updated documentation explaining breaking changes
|
||||
- Provided migration guide
|
||||
- Notified users of upcoming major update
|
||||
|
||||
### 🛠️ How to Modify
|
||||
|
||||
If you need to downgrade the version type:
|
||||
1. Edit the changeset file, change \`major\` to \`minor\` or \`patch\`
|
||||
2. Commit the changes
|
||||
|
||||
### 📚 References
|
||||
|
||||
- [Semantic Versioning](https://semver.org/)
|
||||
- [Changesets Documentation](https://github.com/changesets/changesets)
|
||||
|
||||
---
|
||||
|
||||
*This warning is generated by automated checks to prevent accidental breaking version releases.*`;
|
||||
|
||||
if (botComment) {
|
||||
// Update existing comment
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: botComment.id,
|
||||
body: comment
|
||||
});
|
||||
} else {
|
||||
// Create new comment
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
|
||||
- name: Fail workflow for major changes (fork repos only)
|
||||
if: steps.check-major.outputs.has_major == 'true' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
run: |
|
||||
echo "::error::⚠️ Major version changes detected in fork repository!"
|
||||
echo "::error::"
|
||||
echo "::error::❓ Are you sure this PR contains BREAKING CHANGES?"
|
||||
echo "::error:: Major versions (1.2.3 → 2.0.0) are only for:"
|
||||
echo "::error:: • API removals or incompatible changes"
|
||||
echo "::error:: • Behavior changes that break existing code"
|
||||
echo "::error:: • Major dependency updates with breaking changes"
|
||||
echo "::error::"
|
||||
echo "::error::🚫 Fork repositories cannot submit major version changes due to their breaking nature."
|
||||
echo "::error:: Major changes require repository maintainer approval and coordination."
|
||||
echo "::error::"
|
||||
echo "::error::📝 Please either:"
|
||||
echo "::error:: 1. Change 'major' to 'minor' or 'patch' in your changeset files"
|
||||
echo "::error:: 2. Contact repository maintainers to handle this major change"
|
||||
echo "::error:: 3. Open an issue to discuss the breaking changes first"
|
||||
echo "::error::"
|
||||
echo "::error::For more info about semantic versioning: https://semver.org/"
|
||||
exit 1
|
||||
@@ -0,0 +1,54 @@
|
||||
name: PR - Claude Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
# - "src/**/*.tsx"
|
||||
# - "src/**/*.js"
|
||||
# - "src/**/*.jsx"
|
||||
|
||||
jobs:
|
||||
code-review:
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
# Optional: Filter by PR author
|
||||
# if: |
|
||||
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||
# github.event.pull_request.user.login == 'new-developer' ||
|
||||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code Review
|
||||
id: claude-review
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
prompt: |
|
||||
Please review this pull request and provide feedback on:
|
||||
- Code quality and best practices
|
||||
- Potential bugs or issues
|
||||
- Performance considerations
|
||||
- Security concerns
|
||||
- Test coverage
|
||||
|
||||
Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
|
||||
|
||||
Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
|
||||
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
||||
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
|
||||
@@ -0,0 +1,49 @@
|
||||
name: Bot - Claude Assistant
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude-assistant:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
||||
# claude_args: '--model claude-opus-4-1-20250805 --allowed-tools Bash(gh pr:*)'
|
||||
@@ -0,0 +1,102 @@
|
||||
name: PR - Lint & Label
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
lint-and-label:
|
||||
name: Validate & Auto-label
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Validate PR title
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
chore
|
||||
revert
|
||||
i18n
|
||||
ai
|
||||
|
||||
- name: Auto Label PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const title = context.payload.pull_request.title;
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
|
||||
// Mapping from commit type to label
|
||||
const typeToLabel = {
|
||||
'feat': 'feat',
|
||||
'fix': 'fix',
|
||||
'docs': 'docs',
|
||||
'style': 'style',
|
||||
'refactor': 'refactor',
|
||||
'perf': 'perf',
|
||||
'test': 'test',
|
||||
'build': 'build',
|
||||
'ci': 'ci',
|
||||
'chore': 'chore',
|
||||
'revert': 'revert',
|
||||
'i18n': 'i18n',
|
||||
'ai': 'ai'
|
||||
};
|
||||
|
||||
// Extract type from PR title (format: "type: description" or "type(scope): description")
|
||||
const match = title.match(/^(\w+)(?:\([^)]*\))?(!)?:\s/);
|
||||
|
||||
if (match) {
|
||||
const commitType = match[1];
|
||||
const hasBreakingMark = match[2] === '!';
|
||||
const label = typeToLabel[commitType];
|
||||
|
||||
// Check for breaking change indicator
|
||||
const isBreaking = hasBreakingMark || title.toLowerCase().includes('breaking change');
|
||||
|
||||
if (label) {
|
||||
console.log(`Adding label "${label}" to PR #${prNumber} based on type "${commitType}"`);
|
||||
|
||||
const labelsToAdd = [label];
|
||||
|
||||
// Add breaking-change label if it's a breaking change
|
||||
if (isBreaking) {
|
||||
labelsToAdd.push('breaking-change');
|
||||
console.log(`Also adding "breaking-change" label due to breaking change indicator`);
|
||||
}
|
||||
|
||||
try {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
labels: labelsToAdd
|
||||
});
|
||||
|
||||
console.log(`Successfully added labels: ${labelsToAdd.join(', ')}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to add labels: ${error.message}`);
|
||||
}
|
||||
} else {
|
||||
console.log(`No label mapping found for commit type "${commitType}"`);
|
||||
}
|
||||
} else {
|
||||
console.log(`PR title "${title}" doesn't match conventional commit format`);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
name: PR - Test & Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test-and-build:
|
||||
name: Test & Build
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24'
|
||||
cache: pnpm
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
shell: bash
|
||||
|
||||
- name: Check for eruda imports
|
||||
run: |
|
||||
if grep -r "import.*eruda" src/ --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" | grep -v ":.*[[:space:]]*//.*import.*eruda"; then
|
||||
echo "❌ Found uncommented eruda imports in the codebase!"
|
||||
echo "Please comment out or remove eruda imports before merging."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ No uncommented eruda imports found."
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: ESLint
|
||||
run: pnpm lint
|
||||
|
||||
- name: Type check
|
||||
run: pnpm type-check
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test -- --exclude="**/free-api.test.ts"
|
||||
@@ -0,0 +1,227 @@
|
||||
name: Deploy - Release & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release Packages
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
SKIP_ENV_VALIDATION: true
|
||||
SKIP_PRE_PUSH: true
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24'
|
||||
cache: pnpm
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
shell: bash
|
||||
|
||||
- name: Create Release Pull Request or Tag
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
commit: 'chore(release): version packages'
|
||||
title: 'chore(release): version packages'
|
||||
publish: pnpm run release
|
||||
createGithubReleases: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SKIP_FREE_API: true
|
||||
|
||||
- name: Send Discord Notification
|
||||
if: steps.changesets.outputs.published == 'true'
|
||||
run: |
|
||||
echo "Sending Discord notification for published packages..."
|
||||
|
||||
# Get published packages from changesets output
|
||||
PUBLISHED_PACKAGES='${{ steps.changesets.outputs.publishedPackages }}'
|
||||
|
||||
if [ -z "$PUBLISHED_PACKAGES" ] || [ "$PUBLISHED_PACKAGES" = "[]" ]; then
|
||||
echo "No packages were published"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Published packages: $PUBLISHED_PACKAGES"
|
||||
|
||||
# Process each published package individually
|
||||
echo "$PUBLISHED_PACKAGES" | jq -c '.[]' | while read -r package_info; do
|
||||
if [ -n "$package_info" ]; then
|
||||
PACKAGE_NAME=$(echo "$package_info" | jq -r '.name')
|
||||
PACKAGE_VERSION=$(echo "$package_info" | jq -r '.version')
|
||||
|
||||
echo "Processing package: $PACKAGE_NAME@$PACKAGE_VERSION"
|
||||
|
||||
# Generate tag name based on changesets convention
|
||||
PACKAGE_TAG="$PACKAGE_NAME@$PACKAGE_VERSION"
|
||||
PACKAGE_URL="https://github.com/${{ github.repository }}/releases/tag/$PACKAGE_TAG"
|
||||
|
||||
# Get release info and notes for this specific package tag
|
||||
RELEASE_NOTES_RAW=""
|
||||
SPECIFIC_RELEASE_URL=""
|
||||
|
||||
# Try to get release data for this specific tag
|
||||
RELEASE_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/releases/tags/$PACKAGE_TAG" 2>/dev/null || echo '{}')
|
||||
|
||||
# If specific release doesn't exist, try to get the latest release
|
||||
if [ "$(echo "$RELEASE_DATA" | jq -r '.id // "null"')" = "null" ]; then
|
||||
echo "No specific release found for $PACKAGE_TAG, trying latest release..."
|
||||
LATEST_TAG=$(git describe --abbrev=0 --tags 2>/dev/null || echo "")
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
# Fallback to getting latest release from GitHub API
|
||||
LATEST_TAG=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/releases/latest" \
|
||||
| jq -r '.tag_name // ""')
|
||||
fi
|
||||
|
||||
if [ -n "$LATEST_TAG" ] && [ "$LATEST_TAG" != "null" ]; then
|
||||
RELEASE_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/releases/tags/$LATEST_TAG")
|
||||
SPECIFIC_RELEASE_URL=$(echo "$RELEASE_DATA" | jq -r '.html_url // ""')
|
||||
fi
|
||||
else
|
||||
SPECIFIC_RELEASE_URL=$(echo "$RELEASE_DATA" | jq -r '.html_url // ""')
|
||||
fi
|
||||
|
||||
# Use package URL if no specific release URL found
|
||||
if [ -z "$SPECIFIC_RELEASE_URL" ]; then
|
||||
SPECIFIC_RELEASE_URL="$PACKAGE_URL"
|
||||
fi
|
||||
|
||||
# Extract release notes and clean them up
|
||||
RELEASE_NOTES_RAW=$(echo "$RELEASE_DATA" | jq -r '.body // "No release notes available"')
|
||||
|
||||
# Remove HTML comments and format headers
|
||||
if [ -n "$RELEASE_NOTES_RAW" ] && [ "$RELEASE_NOTES_RAW" != "No release notes available" ]; then
|
||||
RELEASE_NOTES_RAW=$(echo "$RELEASE_NOTES_RAW" | sed 's/<!--[^>]*-->//g')
|
||||
RELEASE_NOTES_RAW=$(echo "$RELEASE_NOTES_RAW" | \
|
||||
sed 's/^## \(.*\)$/**\1**/g' | \
|
||||
sed 's/^### \(.*\)$/▸ **\1**/g' | \
|
||||
sed 's/^#### \(.*\)$/ • **\1**/g' | \
|
||||
sed 's/^##### \(.*\)$/ ◦ **\1**/g')
|
||||
|
||||
# Remove leading/trailing whitespace
|
||||
RELEASE_NOTES_RAW=$(echo "$RELEASE_NOTES_RAW" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
|
||||
# Limit to Discord embed limit (leaving room for other content)
|
||||
if [ ${#RELEASE_NOTES_RAW} -gt 800 ]; then
|
||||
RELEASE_NOTES_RAW=$(echo "$RELEASE_NOTES_RAW" | head -c 800)
|
||||
RELEASE_NOTES_RAW="${RELEASE_NOTES_RAW}..."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get package emoji
|
||||
case "$PACKAGE_NAME" in
|
||||
*"extension"*) EMOJI="🐸" ;;
|
||||
*"website"*) EMOJI="🌐" ;;
|
||||
*"cli"*) EMOJI="⚡" ;;
|
||||
*"api"*) EMOJI="🔌" ;;
|
||||
*"core"*) EMOJI="⚙️" ;;
|
||||
*"sdk"*) EMOJI="🛠️" ;;
|
||||
*) EMOJI="📦" ;;
|
||||
esac
|
||||
|
||||
# Extract display name (e.g., @read-frog/extension -> Extension)
|
||||
PACKAGE_DISPLAY_NAME=$(echo "$PACKAGE_NAME" | sed 's/.*\///g' | sed 's/\b\w/\U&/g')
|
||||
|
||||
TITLE="$EMOJI $PACKAGE_DISPLAY_NAME Release!"
|
||||
DESCRIPTION="**$PACKAGE_DISPLAY_NAME** version \`$PACKAGE_VERSION\` has been released!"
|
||||
|
||||
# Build fields using jq
|
||||
if [ -n "$RELEASE_NOTES_RAW" ] && [ "$RELEASE_NOTES_RAW" != "No release notes available" ]; then
|
||||
FIELDS_JSON=$(jq -n \
|
||||
--arg tag "$PACKAGE_TAG" \
|
||||
--arg release_notes "$RELEASE_NOTES_RAW" \
|
||||
'[
|
||||
{
|
||||
"name": "🏷️ Tag",
|
||||
"value": ("`" + $tag + "`"),
|
||||
"inline": true
|
||||
},
|
||||
{
|
||||
"name": "📝 Release Notes",
|
||||
"value": $release_notes,
|
||||
"inline": false
|
||||
}
|
||||
]')
|
||||
else
|
||||
FIELDS_JSON=$(jq -n \
|
||||
--arg tag "$PACKAGE_TAG" \
|
||||
'[
|
||||
{
|
||||
"name": "🏷️ Tag",
|
||||
"value": ("`" + $tag + "`"),
|
||||
"inline": true
|
||||
}
|
||||
]')
|
||||
fi
|
||||
|
||||
# Create individual embed for this package
|
||||
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
|
||||
EMBED_JSON=$(jq -n \
|
||||
--arg title "$TITLE" \
|
||||
--arg description "$DESCRIPTION" \
|
||||
--arg url "$SPECIFIC_RELEASE_URL" \
|
||||
--argjson fields "$FIELDS_JSON" \
|
||||
--arg timestamp "$TIMESTAMP" \
|
||||
'{
|
||||
title: $title,
|
||||
description: $description,
|
||||
url: $url,
|
||||
color: 48253,
|
||||
fields: $fields,
|
||||
footer: {
|
||||
text: "GitHub Actions",
|
||||
icon_url: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
|
||||
},
|
||||
timestamp: $timestamp
|
||||
}')
|
||||
|
||||
# Create Discord payload for this individual package
|
||||
DISCORD_PAYLOAD=$(echo "$EMBED_JSON" | jq '{embeds: [.]}')
|
||||
|
||||
echo "Discord payload for $PACKAGE_NAME:"
|
||||
echo "$DISCORD_PAYLOAD"
|
||||
|
||||
# Validate JSON before sending
|
||||
if ! echo "$DISCORD_PAYLOAD" | jq empty 2>/dev/null; then
|
||||
echo "Error: Generated invalid JSON payload for $PACKAGE_NAME"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Send individual notification to Discord
|
||||
echo "Sending Discord notification for $PACKAGE_NAME@$PACKAGE_VERSION..."
|
||||
RESPONSE=$(curl -s -w "%{http_code}" -H "Content-Type: application/json" \
|
||||
-X POST \
|
||||
-d "$DISCORD_PAYLOAD" \
|
||||
${{ secrets.DISCORD_WEBHOOK_URL }})
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -c 4)
|
||||
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
|
||||
echo "✅ Successfully sent Discord notification for $PACKAGE_NAME (HTTP $HTTP_CODE)"
|
||||
else
|
||||
echo "❌ Failed to send Discord notification for $PACKAGE_NAME (HTTP $HTTP_CODE)"
|
||||
echo "Response: $RESPONSE"
|
||||
fi
|
||||
|
||||
# Add a small delay between notifications to avoid rate limiting
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,39 @@
|
||||
name: Maintenance - Stale Issues & PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Mark Stale Items
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# ---- Issue settings ----
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 365
|
||||
stale-issue-message: |
|
||||
This issue has been inactive for 60 days and is now marked as stale.
|
||||
It will be automatically closed in 360 days if no further activity occurs.
|
||||
close-issue-message: |
|
||||
Since it has been a long time without updates, the issue has been automatically closed.
|
||||
If you need to continue, please reopen or create a new issue.
|
||||
|
||||
# ---- PR settings ----
|
||||
days-before-pr-stale: 14
|
||||
days-before-pr-close: 30
|
||||
stale-pr-message: |
|
||||
This PR has been inactive for 14 days and is now marked as stale.
|
||||
It will be automatically closed in 30 days if no further activity occurs.
|
||||
close-pr-message: |
|
||||
Since it has been a long time without updates, the PR has been automatically closed.
|
||||
If you need to continue, please reopen or create a new PR.
|
||||
exempt-pr-labels: |
|
||||
pinned
|
||||
WIP
|
||||
Reference in New Issue
Block a user