This commit is contained in:
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: monkeytype
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: monkeytype
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ["https://www.monkeytype.store/"]
|
||||
137
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
137
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Welcome
|
||||
```
|
||||
Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord: discord.gg/monkeytype
|
||||
```
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Did you clear cache before opening an issue?
|
||||
description: Sometimes your browser has old files cached and the bug you are experiencing might be already fixed, or is just a side effect of a new update. If you don't know how to do that, this website should help https://www.pcmag.com/how-to/how-to-clear-your-cache-on-any-browser.
|
||||
options:
|
||||
- label: I have cleared my cache
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please [search](https://github.com/monkeytypegame/monkeytype/issues?q=is%3Aissue) to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have [searched](https://github.com/monkeytypegame/monkeytype/issues?q=is%3Aissue) the existing open and closed issues
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Basic debugging
|
||||
```
|
||||
Below fields are very important to quickly track down the issue, so please take the time to carefully check when the issue happens and when it does not.
|
||||
```
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Does the issue happen when logged in?
|
||||
options: ["Yes", "No", "N/A"]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Does the issue happen when logged out?
|
||||
options: ["Yes", "No"]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Does the issue happen in incognito mode when logged in?
|
||||
options: ["Yes", "No", "N/A"]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Does the issue happen in incognito mode when logged out?
|
||||
options: ["Yes", "No"]
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Account name
|
||||
description: Your Monkeytype account name.
|
||||
placeholder: |
|
||||
Miodec
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Account config
|
||||
description: If your issue only happens when logged in, please provide your config. To export your config, go to the Settings page, scroll all the way down to `import/export settings` and click `export`.
|
||||
placeholder: |
|
||||
Miodec
|
||||
{"theme":"cyberspace","showKeyTips":false,"showLiveWpm":false,"showTimerProgress":false, ... "smoothCaret":true}
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Issue details
|
||||
```
|
||||
Please provide a detailed description of what's happening, and most importantly - solid steps to reproduce the issue. This will help us find it quicker.
|
||||
```
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: A concise description of what you're experiencing.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Environment
|
||||
description: |
|
||||
examples:
|
||||
- **OS**: Windows 10
|
||||
- **Browser**: Google Chrome
|
||||
- **Browser Version**: 94.0.4606.71 (Official Build) (64-bit)
|
||||
value: |
|
||||
- OS:
|
||||
- Browser:
|
||||
- Browser Version:
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Feature Request / Idea
|
||||
url: https://github.com/monkeytypegame/monkeytype/discussions
|
||||
about: Please do not create issues for feature requests. Instead, use GitHub Discussions.
|
||||
28
.github/copilot-instructions.md
vendored
Normal file
28
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Monkeytype AI Coding Instructions
|
||||
|
||||
Make the responses extremely concise. Sacrifice grammar for the sake of concision.
|
||||
|
||||
## Architecture
|
||||
**Monorepo**: pnpm + Turborepo with frontend (Vite + SolidJS), backend (Express + MongoDB + Redis), and shared packages.
|
||||
|
||||
## Commands
|
||||
All commands support `-fe`, `-be`, `-pkg` suffixes for targeted execution:
|
||||
```bash
|
||||
pnpm run lint-fe # Frontend linting
|
||||
pnpm run test-be # Backend + integration tests
|
||||
pnpm run build-pkg # Packages only
|
||||
pnpm run dev # All workspaces with hot reload
|
||||
```
|
||||
|
||||
## SolidJS Migration
|
||||
Frontend is partially migrated - new components use SolidJS (`.tsx`), legacy code remains vanilla JS.
|
||||
|
||||
## Debug Tips
|
||||
- Type/lint errors: Run `pnpm run lint` (OXLint is source of truth, not tsc)
|
||||
|
||||
## Key Files
|
||||
- `turbo.json`: Task deps and caching
|
||||
- `frontend/src/ts/config-metadata.ts`: Config validation rules
|
||||
- `packages/contracts/src/index.ts`: API contract structure
|
||||
- `packages/funbox/src/list.ts`: All funbox definitions
|
||||
- `backend/src/api/routes/index.ts`: ts-rest setup
|
||||
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
versioning-strategy: increase
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
29
.github/labeler.yml
vendored
Normal file
29
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
api:
|
||||
- any: ["frontend/src/ts/ape/**/*", "backend/src/api/**/*"]
|
||||
|
||||
assets:
|
||||
- any: ["frontend/static/**/*"]
|
||||
all: ["!frontend/static/**/*.html"]
|
||||
|
||||
backend:
|
||||
- any: ["backend/**/*"]
|
||||
|
||||
docs:
|
||||
- any: ["**/*.md"]
|
||||
|
||||
frontend:
|
||||
- any: ["frontend/**/*"]
|
||||
|
||||
packages:
|
||||
- any: ["packages/**/*"]
|
||||
|
||||
local dev:
|
||||
- any:
|
||||
[
|
||||
"**/turbo.json",
|
||||
"**/tsconfig.json",
|
||||
"**/knip.json",
|
||||
"**/.prettierrc",
|
||||
"**/.oxlintrc.json",
|
||||
"**/.eslintrc.cjs",
|
||||
]
|
||||
55
.github/pull_request_template.md
vendored
Normal file
55
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
### Description
|
||||
|
||||
<!--
|
||||
Please describe the change(s) made in your PR:
|
||||
- explain the problem being solved
|
||||
- for bug fixes without an open issue, include steps to reproduce the issue
|
||||
- summarize the approach taken
|
||||
|
||||
Use your own words. Do not rely on AI-generated descriptions.
|
||||
They do not demonstrate your understanding of the problem or the solution.
|
||||
Writing the description yourself helps you verify the scope of your work and
|
||||
helps us better understand your intent, reasoning and level of insight.
|
||||
-->
|
||||
|
||||
### Checks
|
||||
|
||||
- [ ] Adding quotes?
|
||||
- Make sure to follow the [quotes documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/QUOTES.md)
|
||||
- [ ] Make sure to include translations for the quotes in the description (or another comment) so we can verify their content.
|
||||
- [ ] Adding a language?
|
||||
- Make sure to follow the [languages documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/LANGUAGES.md)
|
||||
- [ ] Add language to `packages/schemas/src/languages.ts`
|
||||
- [ ] Add language to exactly one group in `frontend/src/ts/constants/languages.ts`
|
||||
- [ ] Add language json file to `frontend/static/languages`
|
||||
- [ ] Adding a theme?
|
||||
- Make sure to follow the [themes documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/THEMES.md)
|
||||
- [ ] Add theme to `packages/schemas/src/themes.ts`
|
||||
- [ ] Add theme to `frontend/src/ts/constants/themes.ts`
|
||||
- [ ] (optional) Add theme css file to `frontend/static/themes`
|
||||
- [ ] Add some screenshots of the theme, especially with different test settings (colorful, flip colors) to your pull request
|
||||
- [ ] Adding a layout?
|
||||
- [ ] Make sure to follow the [layouts documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/LAYOUTS.md)
|
||||
- [ ] Add layout to `packages/schemas/src/layouts.ts`
|
||||
- [ ] Add layout json file to `frontend/static/layouts`
|
||||
- [ ] Adding a font?
|
||||
- Make sure to follow the [fonts documentation](https://github.com/monkeytypegame/monkeytype/blob/master/docs/FONTS.md)
|
||||
- [ ] Add font file to `frontend/static/webfonts`
|
||||
- [ ] Add font to `packages/schemas/src/fonts.ts`
|
||||
- [ ] Add font to `frontend/src/ts/constants/fonts.ts`
|
||||
- [ ] Check if any open issues are related to this PR; if so, be sure to tag them below.
|
||||
- [ ] Make sure the PR title follows the Conventional Commits standard. (https://www.conventionalcommits.org for more info)
|
||||
- [ ] Make sure to include your GitHub username prefixed with @ inside parentheses at the end of the PR title.
|
||||
|
||||
<!-- label(optional scope): pull request title (@your_github_username) -->
|
||||
|
||||
<!-- I know I know they seem boring but please do them, they help us and you will find out it also helps you. -->
|
||||
|
||||
Closes #
|
||||
|
||||
<!-- The issue(s) your PR resolves if any (delete if that is not the case) -->
|
||||
<!-- Please reference any issues and/or PRs related to your pull request -->
|
||||
|
||||
<!-- Pro tip: you can mention an issue, PR, or discussion on GitHub by referencing its hash number, e.g.: [#1234](https://github.com/monkeytypegame/monkeytype/pull/1234) -->
|
||||
|
||||
<!-- Pro tip: you can press . (dot or period) in the code tab of any GitHub repo to get access to GitHub's VS Code web editor. Enjoy! :) -->
|
||||
61
.github/workflows/check-formatting.yml
vendored
Normal file
61
.github/workflows/check-formatting.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Check formatting
|
||||
|
||||
env:
|
||||
PNPM_VERSION: "10.28.1"
|
||||
NODE_VERSION: "24.11.0"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: group-format-check-${{ github.ref }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'force-ci') || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Full checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Install formatter
|
||||
run: pnpm install -D -w oxfmt
|
||||
|
||||
- name: Get changed files
|
||||
id: get-changed-files
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const changedFiles = await github.paginate(
|
||||
github.rest.pulls.listFiles,
|
||||
{
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
}
|
||||
);
|
||||
return changedFiles.filter(file=> file.status !== "removed").map(file => file.filename).join(' ');
|
||||
|
||||
- name: Check formatting (changed files)
|
||||
run: |
|
||||
CHANGED_FILES=$(echo ${{ steps.get-changed-files.outputs.result }})
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
pnpm oxfmt $CHANGED_FILES --check --no-error-on-unmatched-pattern
|
||||
fi
|
||||
23
.github/workflows/check-todo.yml
vendored
Normal file
23
.github/workflows/check-todo.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: PR Todo Checker
|
||||
|
||||
on:
|
||||
pull_request_review_comment:
|
||||
types: [edited, deleted]
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
find_todos:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write # to comment on PRs
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for Todos
|
||||
uses: phntmxyz/pr_todo_checker@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
39
.github/workflows/ci-failure-comment.yml
vendored
Normal file
39
.github/workflows/ci-failure-comment.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Comment on PR for CI Failure
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Monkey CI]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
on-failure:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||
steps:
|
||||
- name: Download workflow artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
- name: Read the pr_num file
|
||||
id: pr_num_reader
|
||||
uses: juliangruber/read-file-action@v1
|
||||
with:
|
||||
path: ./pr_num/pr_num.txt
|
||||
|
||||
- name: Create comment
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
issue-number: ${{ steps.pr_num_reader.outputs.content }}
|
||||
body: |
|
||||
Continuous integration check(s) failed. Please review the [failing check\'s logs](${{ github.event.workflow_run.html_url }}) and make the necessary changes.
|
||||
|
||||
- name: Apply label changes
|
||||
uses: PauMAVA/add-remove-label-action@v1.0.3
|
||||
with:
|
||||
issue_number: ${{ steps.pr_num_reader.outputs.content }}
|
||||
add: "waiting for update"
|
||||
remove: "waiting for review"
|
||||
40
.github/workflows/claude-code-review.yml
vendored
Normal file
40
.github/workflows/claude-code-review.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Claude Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, ready_for_review, reopened]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
# - "src/**/*.tsx"
|
||||
# - "src/**/*.js"
|
||||
# - "src/**/*.jsx"
|
||||
|
||||
jobs:
|
||||
claude-review:
|
||||
if: >-
|
||||
contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association)
|
||||
|
||||
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 }}
|
||||
plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
|
||||
plugins: "code-review@claude-code-plugins"
|
||||
prompt: "/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
51
.github/workflows/claude.yml
vendored
Normal file
51
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association))
|
||||
)
|
||||
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://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
70
.github/workflows/fix-formatting.yml
vendored
Normal file
70
.github/workflows/fix-formatting.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Fix formatting
|
||||
|
||||
env:
|
||||
PNPM_VERSION: "10.28.1"
|
||||
NODE_VERSION: "24.11.0"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'format'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name}}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Install formatter
|
||||
run: pnpm install -D -w oxfmt --ignore-scripts
|
||||
|
||||
- name: Get changed files
|
||||
id: get-changed-files
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const changedFiles = await github.paginate(
|
||||
github.rest.pulls.listFiles,
|
||||
{
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
}
|
||||
);
|
||||
return changedFiles.filter(file=> file.status !== "removed").map(file => file.filename).join(' ');
|
||||
|
||||
- name: Fix formatting
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.get-changed-files.outputs.result }}
|
||||
run: |
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "$CHANGED_FILES" | tr ' ' '\n' | xargs pnpm oxfmt --no-error-on-unmatched-pattern
|
||||
fi
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "fix formatting"
|
||||
|
||||
- name: Remove label
|
||||
uses: actions-ecosystem/action-remove-labels@v1
|
||||
with:
|
||||
labels: format
|
||||
14
.github/workflows/labeler.yml
vendored
Normal file
14
.github/workflows/labeler.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
with:
|
||||
repo-token: "${{ secrets.API_TOKEN }}"
|
||||
346
.github/workflows/monkey-ci.yml
vendored
Normal file
346
.github/workflows/monkey-ci.yml
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
name: Monkey CI
|
||||
|
||||
env:
|
||||
PNPM_VERSION: "10.28.1"
|
||||
NODE_VERSION: "24.11.0"
|
||||
RECAPTCHA_SITE_KEY: "6Lc-V8McAAAAAJ7s6LGNe7MBZnRiwbsbiWts87aj"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
concurrency:
|
||||
group: group-${{ github.ref }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pre-ci:
|
||||
if: github.event.pull_request.draft == false || contains(github.event.pull_request.labels.*.name, 'force-ci') || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
name: pre-ci
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should-build-be: ${{ steps.export-changes.outputs.should-build-be }}
|
||||
should-build-fe: ${{ steps.export-changes.outputs.should-build-fe }}
|
||||
should-build-pkg: ${{ steps.export-changes.outputs.should-build-pkg }}
|
||||
assets-json: ${{ steps.export-changes.outputs.assets-json }}
|
||||
|
||||
steps:
|
||||
- name: Full checkout
|
||||
uses: actions/checkout@v4
|
||||
# paths filter doesn't need checkout on pr
|
||||
if: github.event_name != 'pull_request'
|
||||
|
||||
- name: Detect changes
|
||||
uses: dorny/paths-filter@v4
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
json:
|
||||
- 'frontend/static/**/*'
|
||||
be-src:
|
||||
- 'backend/**/*.{ts,js,json,lua,css,html}'
|
||||
- 'backend/package.json'
|
||||
fe-src:
|
||||
- 'frontend/**/*.{ts,scss,html}'
|
||||
- 'frontend/package.json'
|
||||
pkg-src:
|
||||
- 'packages/**/*'
|
||||
anti-cheat:
|
||||
- 'backend/**/anticheat/**'
|
||||
|
||||
- name: Check Anti-cheat
|
||||
if: steps.filter.outputs.anti-cheat == 'true' && !contains(github.event.pull_request.labels.*.name, 'force-ci') && !contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
run: exit 1
|
||||
|
||||
- name: Export changes
|
||||
id: export-changes
|
||||
run: |
|
||||
echo "should-build-pkg=${{ steps.filter.outputs.pkg-src }}" >> $GITHUB_OUTPUT
|
||||
echo "should-build-be=${{ steps.filter.outputs.be-src }}" >> $GITHUB_OUTPUT
|
||||
echo "should-build-fe=${{ steps.filter.outputs.fe-src }}" >> $GITHUB_OUTPUT
|
||||
echo "assets-json=${{ steps.filter.outputs.json }}" >> $GITHUB_OUTPUT
|
||||
|
||||
prime-cache:
|
||||
name: prime-cache
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pre-ci]
|
||||
if: needs.pre-ci.outputs.should-build-be == 'true' || needs.pre-ci.outputs.should-build-fe == 'true' || needs.pre-ci.outputs.should-build-pkg == 'true' || needs.pre-ci.outputs.assets-json == 'true' || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
steps:
|
||||
- name: Checkout pnpm-lock
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
pnpm-lock.yaml
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-pnpm
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: node-modules
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
lookup-only: true
|
||||
|
||||
- if: ${{ steps.cache-pnpm.outputs.cache-hit != 'true' }}
|
||||
name: Full checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- if: ${{ steps.cache-pnpm.outputs.cache-hit != 'true' }}
|
||||
name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- if: ${{ steps.cache-pnpm.outputs.cache-hit != 'true' }}
|
||||
name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
ci-be:
|
||||
name: ci-be
|
||||
needs: [pre-ci, prime-cache]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.pre-ci.outputs.should-build-be == 'true' || needs.pre-ci.outputs.should-build-pkg == 'true' || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
backend
|
||||
packages
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-pnpm
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: node-modules
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Check lint
|
||||
run: npm run lint-fast-be && npm run lint-be
|
||||
|
||||
- name: Build
|
||||
run: npm run build-be
|
||||
|
||||
- name: Test
|
||||
run: npm run test-be
|
||||
|
||||
ci-fe:
|
||||
name: ci-fe
|
||||
needs: [pre-ci, prime-cache]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.pre-ci.outputs.should-build-fe == 'true' || needs.pre-ci.outputs.should-build-pkg == 'true' || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
frontend
|
||||
packages
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Create stub firebase config
|
||||
working-directory: ./frontend/src/ts/constants
|
||||
run: mv ./firebase-config-example.ts ./firebase-config.ts && cp ./firebase-config.ts ./firebase-config-live.ts
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-pnpm
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: node-modules
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Check lint
|
||||
run: npm run lint-fast-fe && npm run lint-fe
|
||||
|
||||
- name: Build
|
||||
run: npm run build-fe
|
||||
|
||||
- name: Test
|
||||
run: npm run test-fe
|
||||
|
||||
ci-assets:
|
||||
name: ci-assets
|
||||
needs: [pre-ci, prime-cache]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.pre-ci.outputs.assets-json == 'true' || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
frontend
|
||||
packages
|
||||
|
||||
- uses: dorny/paths-filter@v4
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
languages:
|
||||
- 'frontend/static/languages/**'
|
||||
quotes:
|
||||
- 'frontend/static/quotes/**'
|
||||
others:
|
||||
- 'frontend/static/layouts/**'
|
||||
- 'frontend/static/themes/**'
|
||||
- 'frontend/static/webfonts/**'
|
||||
- 'frontend/static/challenges/**'
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-pnpm
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: node-modules
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Lint JSON
|
||||
run: npm run lint-json-assets
|
||||
|
||||
- name: Validate language assets
|
||||
if: steps.filter.outputs.languages == 'true'
|
||||
run: npm run check-assets-languages
|
||||
|
||||
- name: Validate quote assets
|
||||
if: steps.filter.outputs.quotes == 'true'
|
||||
run: npm run check-assets-quotes
|
||||
|
||||
- name: Validate other assets
|
||||
if: steps.filter.outputs.others == 'true'
|
||||
run: npm run check-assets-others
|
||||
|
||||
ci-pkg:
|
||||
name: ci-pkg
|
||||
needs: [pre-ci, prime-cache]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.pre-ci.outputs.should-build-pkg == 'true' || contains(github.event.pull_request.labels.*.name, 'force-full-ci')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
packages
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache node modules
|
||||
id: cache-pnpm
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: node-modules
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Check lint
|
||||
run: npm run lint-fast-pkg && npm run lint-pkg
|
||||
|
||||
- name: Build
|
||||
run: npm run build-pkg
|
||||
|
||||
- name: Test
|
||||
run: npm run test-pkg
|
||||
|
||||
on-failure:
|
||||
name: on-failure
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ci-be, ci-fe, ci-assets, ci-pkg]
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') && github.ref != 'refs/heads/master' }}
|
||||
steps:
|
||||
- name: Save the PR number in an artifact
|
||||
shell: bash
|
||||
env:
|
||||
PR_NUM: ${{ github.event.number }}
|
||||
run: echo $PR_NUM > pr_num.txt
|
||||
|
||||
- name: Upload the PR number
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr_num
|
||||
path: ./pr_num.txt
|
||||
87
.github/workflows/publish-docker-images.yml
vendored
Normal file
87
.github/workflows/publish-docker-images.yml
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
name: Publish Docker image
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
env:
|
||||
BE_REPO: monkeytype/monkeytype-backend
|
||||
FE_REPO: monkeytype/monkeytype-frontend
|
||||
PLATFORMS: linux/amd64,linux/arm64
|
||||
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
||||
- name: Backend extract metadata (tags, labels)
|
||||
id: bemeta
|
||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
|
||||
with:
|
||||
images: ${{ env.BE_REPO }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Backend build and push Docker image
|
||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
file: ./docker/backend/Dockerfile
|
||||
push: true
|
||||
tags: ${{ env.BE_REPO }}:latest,${{ steps.bemeta.outputs.tags }}
|
||||
labels: ${{ steps.bemeta.outputs.labels }}
|
||||
build-args: |
|
||||
server_version: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Backend publish description
|
||||
uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
repository: ${{ env.BE_REPO }}
|
||||
short-description: Official backend server for monkeytype.com
|
||||
readme-filepath: ./docs/SELF_HOSTING.md
|
||||
|
||||
- name: Frontend extract metadata (tags, labels)
|
||||
id: femeta
|
||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
|
||||
with:
|
||||
images: ${{ env.FE_REPO }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Frontend build and push Docker image
|
||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
file: ./docker/frontend/Dockerfile
|
||||
push: true
|
||||
tags: ${{ env.FE_REPO }}:latest,${{ steps.femeta.outputs.tags }}
|
||||
labels: ${{ steps.femeta.outputs.labels }}
|
||||
|
||||
- name: Frontend publish description
|
||||
uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
repository: ${{ env.FE_REPO }}
|
||||
short-description: Official frontend server for monkeytype.com
|
||||
readme-filepath: ./docs/SELF_HOSTING.md
|
||||
73
.github/workflows/semantic-pr-title.yml
vendored
Normal file
73
.github/workflows/semantic-pr-title.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: "Semantic PR Title"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
- reopened
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: check
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
|
||||
steps:
|
||||
- name: Lint and verify PR title
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
id: lint_pr_title
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
build
|
||||
chore
|
||||
ci
|
||||
docs
|
||||
feat
|
||||
impr
|
||||
fix
|
||||
perf
|
||||
refactor
|
||||
revert
|
||||
style
|
||||
test
|
||||
requireScope: false
|
||||
subjectPattern: ^.+ \(@[^ ,]+(, @[^ ,]+)*\)$
|
||||
subjectPatternError: |
|
||||
Title "{title}"
|
||||
didn't match the configured pattern. Please ensure that the title
|
||||
contains your name so that you can be credited in our changelog.
|
||||
|
||||
- uses: marocchino/sticky-pull-request-comment@v2
|
||||
# When the previous steps fails, the workflow would stop. By adding this
|
||||
# condition you can continue the execution with the populated error message.
|
||||
if: always() && (steps.lint_pr_title.outputs.error_message != null)
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
message: |
|
||||
Hey there and thank you for opening this pull request! 👋🏼
|
||||
|
||||
We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and also include the author name at the end inside parenthesis. It looks like your proposed title needs to be adjusted.
|
||||
|
||||
Details:
|
||||
|
||||
```
|
||||
${{ steps.lint_pr_title.outputs.error_message }}
|
||||
```
|
||||
A correct version would look something like:
|
||||
|
||||
feat: add new feature (@github_username)
|
||||
impr(quotes): add english quotes (@username)
|
||||
fix(leaderboard): show user rank correctly (@user1, @user2, @user3)
|
||||
|
||||
# Delete a previous comment when the issue has been resolved
|
||||
- if: ${{ steps.lint_pr_title.outputs.error_message == null }}
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
delete: true
|
||||
16
.github/workflows/stale-pr.yml
vendored
Normal file
16
.github/workflows/stale-pr.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: "Mark Stale PRs"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 20 * * *"
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
stale-pr-message: "This PR is stale. Please trigger a re-run of the PR check action."
|
||||
days-before-stale: 7
|
||||
100
.github/workflows/update-labels.yml
vendored
Normal file
100
.github/workflows/update-labels.yml
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
name: Check labels to update
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
pull-requests: read
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
[
|
||||
review_requested,
|
||||
ready_for_review,
|
||||
review_request_removed,
|
||||
converted_to_draft,
|
||||
synchronize,
|
||||
edited,
|
||||
]
|
||||
pull_request_review:
|
||||
types: [submitted, edited, dismissed]
|
||||
pull_request_review_comment:
|
||||
types: [created, edited]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
jobs:
|
||||
update-labels:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PR_NUM: ${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
|
||||
steps:
|
||||
- name: Set up varibles
|
||||
run: |
|
||||
echo "REVIEW=0" >> $GITHUB_ENV
|
||||
echo "UPDATE=0" >> $GITHUB_ENV
|
||||
|
||||
- name: Add 'waiting for review' label
|
||||
# when a review is requested or if the PR is converted from a draft
|
||||
if: |
|
||||
github.event_name == 'pull_request_target' &&
|
||||
contains(fromJSON('["review_requested", "ready_for_review"]'), github.event.action)
|
||||
run: echo "REVIEW=1" >> $GITHUB_ENV
|
||||
|
||||
- name: Remove 'waiting for review' label
|
||||
# when a review request is removed or if the PR is converted to a draft
|
||||
# or when the PR is reviewed by the owner, a member or a collaborator
|
||||
if: |
|
||||
(
|
||||
github.event_name == 'pull_request_target' &&
|
||||
contains(fromJSON('["review_request_removed", "converted_to_draft"]'), github.event.action)
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'pull_request_review' &&
|
||||
contains(fromJSON('["submitted", "edited"]'), github.event.action) &&
|
||||
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
|
||||
)
|
||||
run: echo "REVIEW=-1" >> $GITHUB_ENV
|
||||
|
||||
- name: Add 'waiting for update' label
|
||||
# when a review by one of {owner, member, collaborator} requests changes
|
||||
if: |
|
||||
github.event_name == 'pull_request_review' &&
|
||||
github.event.review.state == 'changes_requested' &&
|
||||
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
|
||||
run: echo "UPDATE=1" >> $GITHUB_ENV
|
||||
|
||||
- name: Remove 'waiting for update' label from PR/issue
|
||||
# when PR is commited to or if the PR is edited or if a review is requested or dismissed
|
||||
# or when a comment is added by the author to the review or to the main PR thread
|
||||
if: |
|
||||
(
|
||||
github.event_name == 'pull_request_target' &&
|
||||
contains(fromJSON('["synchronize", "edited", "review_requested"]'), github.event.action)
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'pull_request_review' &&
|
||||
github.event.action == 'dismissed'
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'pull_request_review_comment' &&
|
||||
contains(fromJSON('["created", "edited"]'), github.event.action) &&
|
||||
github.event.comment.user.id == github.event.pull_request.user.id
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'issue_comment' &&
|
||||
contains(fromJSON('["created", "edited"]'), github.event.action) &&
|
||||
github.event.comment.user.id == github.event.issue.user.id
|
||||
)
|
||||
run: echo "UPDATE=-1" >> $GITHUB_ENV
|
||||
|
||||
- name: Save result in a JSON file
|
||||
env:
|
||||
LABELS_JSON: ${{ format('{{"waiting_for_review"{0} "{1}", "waiting_for_update"{0} "{2}", "pr_num"{0} "{3}"}}', ':', env.REVIEW, env.UPDATE, env.PR_NUM) }}
|
||||
run: echo $LABELS_JSON > write-labels.json
|
||||
|
||||
- name: Upload the JSON file
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: labels
|
||||
path: ./write-labels.json
|
||||
52
.github/workflows/write-labels.yml
vendored
Normal file
52
.github/workflows/write-labels.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: Write label on PR/issue
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Check labels to update]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
write-labels:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download workflow artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
- name: Read json file
|
||||
id: json_reader
|
||||
uses: juliangruber/read-file-action@v1
|
||||
with:
|
||||
path: ./labels/write-labels.json
|
||||
|
||||
- name: Add `waiting for review` label
|
||||
if: fromJSON(steps.json_reader.outputs.content).waiting_for_review == 1
|
||||
run: echo "ADD_LABELS=${ADD_LABELS}waiting for review," >> $GITHUB_ENV
|
||||
|
||||
- name: Remove `waiting for review` label
|
||||
if: fromJSON(steps.json_reader.outputs.content).waiting_for_review == -1
|
||||
run: echo "REMOVE_LABELS=${REMOVE_LABELS}waiting for review," >> $GITHUB_ENV
|
||||
|
||||
- name: Add `waiting for update` label
|
||||
if: fromJSON(steps.json_reader.outputs.content).waiting_for_update == 1
|
||||
run: echo "ADD_LABELS=${ADD_LABELS}waiting for update," >> $GITHUB_ENV
|
||||
|
||||
- name: Remove `waiting for update` label
|
||||
if: fromJSON(steps.json_reader.outputs.content).waiting_for_update == -1
|
||||
run: echo "REMOVE_LABELS=${REMOVE_LABELS}waiting for update," >> $GITHUB_ENV
|
||||
|
||||
- name: Apply label changes
|
||||
if: env.ADD_LABELS || env.REMOVE_LABELS
|
||||
uses: PauMAVA/add-remove-label-action@v1.0.3
|
||||
with:
|
||||
issue_number: ${{ fromJSON(steps.json_reader.outputs.content).pr_num }}
|
||||
add: ${{ env.ADD_LABELS }}
|
||||
remove: ${{ env.REMOVE_LABELS }}
|
||||
Reference in New Issue
Block a user