diff --git a/.eslintrc.js b/.eslintrc.js
index 5da22e72d..ff3ec59c8 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -78,6 +78,7 @@ module.exports = {
"keyword-spacing": "warn",
"space-infix-ops": "error",
"arrow-spacing": "warn",
+ "no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-constant-condition": [ "error", {
"checkLoops": false,
diff --git a/.github/ISSUE_TEMPLATE/ask_for_help.yml b/.github/ISSUE_TEMPLATE/ask_for_help.yml
index 45bd046e5..2156c5be0 100644
--- a/.github/ISSUE_TEMPLATE/ask_for_help.yml
+++ b/.github/ISSUE_TEMPLATE/ask_for_help.yml
@@ -3,7 +3,7 @@ name: ❓ Ask for help
description: |
Submit any question related to Uptime Kuma
#title: "[Help]"
-labels: ["help", "P3-low"]
+labels: ["help"]
body:
- type: markdown
attributes:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 31cd6faf6..d0330c70a 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -3,7 +3,7 @@ name: 🐛 Bug Report
description: |
Submit a bug report to help us improve
#title: "[Bug]"
-labels: ["bug", "P2-medium"]
+labels: ["bug"]
body:
- type: markdown
attributes:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index c9ec4d093..61d647a4f 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -3,28 +3,15 @@ name: 🚀 Feature Request
description: |
Submit a proposal for a new feature
# title: "[Feature]"
-labels: ["feature-request", "P3-low"]
+labels: ["feature-request"]
body:
- type: markdown
attributes:
value: |
- ## ❗Important Announcement
-
- ### 🚧 Temporary Delay in Feature Requests and Pull Request Reviews
-
- **At this time, we may be slower to respond to new feature requests and review pull requests. Existing requests and PRs will remain in the backlog but may not be prioritized immediately.**
-
- - **Reason**: Our current focus is on addressing bugs, improving system performance, and implementing essential updates. This will help stabilize the project and ensure smoother management.
- - **Impact**: While no new feature requests or pull requests are being outright rejected, there may be significant delays in reviews. We encourage the community to help by reviewing PRs or assisting other users in the meantime.
- - **What You Can Do**: If you're interested in contributing, reviewing open PRs by following our [Review Guidelines](https://github.com/louislam/uptime-kuma/blob/master/.github/REVIEW_GUIDELINES.md) or offering help to other users is greatly appreciated. All feature requests and PRs will be revisited once the suspension period is lifted.
-
- We appreciate your patience and understanding as we continue to improve Uptime Kuma.
-
### 🚫 Please Avoid Unnecessary Pinging of Maintainers
- **We kindly ask you to refrain from pinging maintainers unless absolutely necessary. Pings are reserved for critical/urgent pull requests that require immediate attention.**
-
- **Why**: Reserving pings for urgent matters ensures maintainers can prioritize critical tasks effectively.
+ We kindly ask you to refrain from pinging maintainers unless absolutely necessary.
+ Pings are for critical/urgent pull requests that require immediate attention.
- type: textarea
id: related-issues
validations:
diff --git a/.github/ISSUE_TEMPLATE/security_issue.yml b/.github/ISSUE_TEMPLATE/security_issue.yml
index d49c0aaf5..247073102 100644
--- a/.github/ISSUE_TEMPLATE/security_issue.yml
+++ b/.github/ISSUE_TEMPLATE/security_issue.yml
@@ -3,7 +3,7 @@ name: 🛡️ Security Issue
description: |
Notify Louis Lam about a security concern. Please do NOT include any sensitive details in this issue.
# title: "Security Issue"
-labels: ["security", "P1-high"]
+labels: ["security"]
assignees: [louislam]
body:
- type: markdown
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index f639c395e..e351aa2e2 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,44 +1,35 @@
-**⚠️ Please Note: We do not accept all types of pull requests, and we want to ensure we don’t waste your time. Before submitting, make sure you have read our pull request guidelines: [Pull Request Rules](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)**
-
-## ❗ Important Announcement
+## ❗ Important Announcements
Click here for more details:
-### 🚧 Temporary Delay in Feature Requests and Pull Request Reviews
-
-**At this time, we may be slower to respond to new feature requests and review pull requests. Existing requests and PRs will remain in the backlog but may not be prioritized immediately.**
-
-- **Reason**: Our current focus is on addressing bugs, improving system performance, and implementing essential updates. This will help stabilize the project and ensure smoother management.
-- **Impact**: While no new feature requests or pull requests are being outright rejected, there may be significant delays in reviews. We encourage the community to help by reviewing PRs or assisting other users in the meantime.
-- **What You Can Do**: If you're interested in contributing, reviewing open PRs by following our [Review Guidelines](https://github.com/louislam/uptime-kuma/blob/master/.github/REVIEW_GUIDELINES.md) or offering support to other users is greatly appreciated. All feature requests and PRs will be revisited once the suspension period is lifted.
-
-We appreciate your patience and understanding as we continue to improve Uptime Kuma.
+**⚠️ Please Note: We do not accept all types of pull requests, and we want to ensure we don’t waste your time. Before submitting, make sure you have read our pull request guidelines: [Pull Request Rules](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)**
### 🚫 Please Avoid Unnecessary Pinging of Maintainers
-**We kindly ask you to refrain from pinging maintainers unless absolutely necessary. Pings are reserved for critical/urgent pull requests that require immediate attention.**
-
-**Why**: Reserving pings for urgent matters ensures maintainers can prioritize critical tasks effectively.
+We kindly ask you to refrain from pinging maintainers unless absolutely necessary. Pings are for critical/urgent pull requests that require immediate attention.
## 📋 Overview
-Provide a clear summary of the purpose and scope of this pull request:
+
- **What problem does this pull request address?**
-
- Please provide a detailed explanation here.
-
- **What features or functionality does this pull request introduce or enhance?**
-
- Please provide a detailed explanation here.
-## 🔄 Changes
+
-### 🛠️ Type of change
+- Relates to #issue-number
+- Resolves #issue-number
+
+## 🛠️ Type of change
@@ -52,23 +43,12 @@ Provide a clear summary of the purpose and scope of this pull request:
- [ ] 🔧 Other (please specify):
- Provide additional details here.
-## 🔗 Related Issues
-
-
-
-- Relates to #issue-number
-- Resolves #issue-number
-- Fixes #issue-number
-
-## 📄 Checklist *
+## 📄 Checklist
- [ ] 🔍 My code adheres to the style guidelines of this project.
+- [ ] 🦿 I have indicated where (if any) I used an LLM for the contributions
- [ ] ✅ I ran ESLint and other code linters for modified files.
- [ ] 🛠️ I have reviewed and tested my code.
- [ ] 📝 I have commented my code, especially in hard-to-understand areas (e.g., using JSDoc for methods).
@@ -82,10 +62,11 @@ Please link any GitHub issues or tasks that this pull request addresses. Use the
## 📷 Screenshots or Visual Changes
- **UI Modifications**: Highlight any changes made to the user interface.
@@ -97,26 +78,3 @@ If not, remove this section.
| `DOWN` |  |  |
| Certificate-expiry |  |  |
| Testing |  |  |
-
-## ℹ️ Additional Context
-
-Provide any relevant details to assist reviewers in understanding the changes.
-
-Click here for more details:
-
-
-**Key Considerations**:
-
-- **Design decisions** – Key choices or trade-offs made during development.
-- **Alternative solutions** – Approaches considered but not implemented, along with reasons.
-- **Relevant links** – Specifications, discussions, or resources that provide context.
-- **Dependencies** – Related pull requests or issues that must be resolved before merging.
-- **Additional context** – Any other details that may help reviewers understand the changes.
-
-Provide details here
-
-## 💬 Requested Feedback
-
-
-
-- `Mention documents needing feedback here`
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 000000000..f29b9f4b3
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,167 @@
+# Copilot Instructions for Uptime Kuma
+
+## Copilot's Goals/Tasks
+
+- Check spelling
+- Do not show "Pull Request Overview"
+- You do not have to reply if there are no issues
+
+## Repository Overview
+
+**Uptime Kuma** is a self-hosted monitoring tool for HTTP(s), TCP, DNS, Docker, etc. Built with Vue 3 (frontend) and Node.js/Express (backend), using Socket.IO for real-time communication.
+
+- **Languages**: JavaScript, Vue 3, TypeScript (limited), HTML, CSS/SCSS
+- **Backend**: Node.js >= 20.4, Express.js, Socket.IO, SQLite
+- **Frontend**: Vue 3, Vite, Bootstrap 5, Chart.js
+- **Package Manager**: npm with `legacy-peer-deps=true` (.npmrc)
+
+## Build & Validation Commands
+
+### Prerequisites
+- Node.js >= 20.4.0, npm >= 9.3, Git
+
+### Essential Command Sequence
+
+1. **Install Dependencies**:
+ ```bash
+ npm ci # Use npm ci NOT npm install (~60-90 seconds)
+ ```
+
+2. **Linting** (required before committing):
+ ```bash
+ npm run lint # Both linters (~15-30 seconds)
+ npm run lint:prod # For production (zero warnings)
+ ```
+
+3. **Build Frontend**:
+ ```bash
+ npm run build # Takes ~90-120 seconds, builds to dist/
+ ```
+
+4. **Run Tests**:
+ ```bash
+ npm run test-backend # Backend tests (~50-60 seconds)
+ npm test # All tests
+ ```
+
+### Development Workflow
+
+```bash
+npm run dev # Starts frontend (port 3000) and backend (port 3001)
+```
+
+## Project Architecture
+
+### Directory Structure
+
+```
+/
+├── server/ Backend source code
+│ ├── model/ Database models (auto-mapped to tables)
+│ ├── monitor-types/ Monitor type implementations
+│ ├── notification-providers/ Notification integrations
+│ ├── routers/ Express routers
+│ ├── socket-handlers/ Socket.IO event handlers
+│ ├── server.js Server entry point
+│ └── uptime-kuma-server.js Main server logic
+├── src/ Frontend source code (Vue 3 SPA)
+│ ├── components/ Vue components
+│ ├── pages/ Page components
+│ ├── lang/ i18n translations
+│ ├── router.js Vue Router configuration
+│ └── main.js Frontend entry point
+├── db/ Database related
+│ ├── knex_migrations/ Knex migration files
+│ └── kuma.db SQLite database (gitignored)
+├── test/ Test files
+│ ├── backend-test/ Backend unit tests
+│ └── e2e/ Playwright E2E tests
+├── config/ Build configuration
+│ ├── vite.config.js Vite build config
+│ └── playwright.config.js Playwright test config
+├── dist/ Frontend build output (gitignored)
+├── data/ App data directory (gitignored)
+├── public/ Static frontend assets (dev only)
+├── docker/ Docker build files
+└── extra/ Utility scripts
+```
+
+### Key Configuration Files
+
+- **package.json**: Scripts, dependencies, Node.js version requirement
+- **.eslintrc.js**: ESLint rules (4 spaces, double quotes, unix line endings, JSDoc required)
+- **.stylelintrc**: Stylelint rules (4 spaces indentation)
+- **.editorconfig**: Editor settings (4 spaces, LF, UTF-8)
+- **tsconfig-backend.json**: TypeScript config for backend (only src/util.ts)
+- **.npmrc**: `legacy-peer-deps=true` (required for dependency resolution)
+- **.gitignore**: Excludes node_modules, dist, data, tmp, private
+
+### Code Style (strictly enforced by linters)
+
+- 4 spaces indentation, double quotes, Unix line endings (LF), semicolons required
+- **Naming**: JavaScript/TypeScript (camelCase), SQLite (snake_case), CSS/SCSS (kebab-case)
+- JSDoc required for all functions/methods
+
+## CI/CD Workflows
+
+**auto-test.yml** (runs on PR/push to master/1.23.X):
+- Linting, building, backend tests on multiple OS/Node versions (15 min timeout)
+- E2E Playwright tests
+
+**validate.yml**: Validates JSON/YAML files, language files, knex migrations
+
+**PR Requirements**: All linters pass, tests pass, code follows style guidelines
+
+## Common Issues
+
+1. **npm install vs npm ci**: Always use `npm ci` for reproducible builds
+2. **TypeScript errors**: `npm run tsc` shows 1400+ errors - ignore them, they don't affect builds
+3. **Stylelint warnings**: Deprecation warnings are expected, ignore them
+4. **Test failures**: Always run `npm run build` before running tests
+5. **Port conflicts**: Dev server uses ports 3000 and 3001
+6. **First run**: Server shows "db-config.json not found" - this is expected, starts setup wizard
+
+## Translations
+
+- Managed via Weblate. Add keys to `src/lang/en.json` only
+- Don't include other languages in PRs
+- Use `$t("key")` in Vue templates
+
+## Database
+
+- Primary: SQLite (also supports MariaDB/MySQL/PostgreSQL)
+- Migrations in `db/knex_migrations/` using Knex.js
+- Filename format validated by CI: `node ./extra/check-knex-filenames.mjs`
+
+## Testing
+
+- **Backend**: Node.js test runner, fast unit tests
+- **E2E**: Playwright (requires `npx playwright install` first time)
+- Test data in `data/playwright-test`
+
+## Adding New Features
+
+### New Notification Provider
+Files to modify:
+1. `server/notification-providers/PROVIDER_NAME.js` (backend logic)
+2. `server/notification.js` (register provider)
+3. `src/components/notifications/PROVIDER_NAME.vue` (frontend UI)
+4. `src/components/notifications/index.js` (register frontend)
+5. `src/components/NotificationDialog.vue` (add to list)
+6. `src/lang/en.json` (add translation keys)
+
+### New Monitor Type
+Files to modify:
+1. `server/monitor-types/MONITORING_TYPE.js` (backend logic)
+2. `server/uptime-kuma-server.js` (register monitor type)
+3. `src/pages/EditMonitor.vue` (frontend UI)
+4. `src/lang/en.json` (add translation keys)
+
+## Important Notes
+
+1. **Trust these instructions** - based on testing. Search only if incomplete/incorrect
+2. **Dependencies**: 5 known vulnerabilities (3 moderate, 2 high) - acknowledged, don't fix without discussion
+3. **Git Branches**: `master` (v2 development), `1.23.X` (v1 maintenance)
+4. **Node Version**: >= 20.4.0 required
+5. **Socket.IO**: Most backend logic in `server/socket-handlers/`, not REST
+6. **Never commit**: `data/`, `dist/`, `tmp/`, `private/`, `node_modules/`
diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml
index f58229c7c..46fe5d23f 100644
--- a/.github/workflows/auto-test.yml
+++ b/.github/workflows/auto-test.yml
@@ -21,16 +21,20 @@ jobs:
strategy:
matrix:
- os: [macos-latest, ubuntu-latest, windows-latest, ARM64]
- node: [ 18, 20 ]
+ os: [macos-latest, ubuntu-22.04, windows-latest, ARM64]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+ node: [ 20, 24 ]
+ # Also test non-LTS, but only on Ubuntu.
+ include:
+ - os: ubuntu-22.04
+ node: 25
steps:
- run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: npm install
@@ -49,7 +53,7 @@ jobs:
strategy:
matrix:
os: [ ARMv7 ]
- node: [ 18, 20 ]
+ node: [ 20, 22 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -57,7 +61,7 @@ jobs:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- run: npm ci --production
@@ -70,7 +74,7 @@ jobs:
- uses: actions/checkout@v4
- name: Use Node.js 20
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: 20
- run: npm install
@@ -84,7 +88,7 @@ jobs:
- uses: actions/checkout@v4
- name: Use Node.js 20
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: 20
- run: npm install
diff --git a/.github/workflows/close-incorrect-issue.yml b/.github/workflows/close-incorrect-issue.yml
index 3ef5ba378..9d4616931 100644
--- a/.github/workflows/close-incorrect-issue.yml
+++ b/.github/workflows/close-incorrect-issue.yml
@@ -11,13 +11,13 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
- node-version: [18]
+ node-version: [20]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 7e631ccd4..4dff3689d 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -32,7 +32,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: 20
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 968f0dc51..e4cae2ad0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,7 +86,7 @@ to review the appropriate one for your contribution.
PR:
- A text may not be currently localisable. In this case, **adding a new
- language key** via `$t("languageKey")` might be nessesary
+ language key** via `$t("languageKey")` might be necessary
- language keys need to be **added to `en.json`** to be visible in weblate. If
this has not happened, a PR is appreciated.
- **Adding a new language** requires a new file see
diff --git a/README.md b/README.md
index d0b1ac17e..ecae0e288 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Uptime Kuma is an easy-to-use self-hosted monitoring tool.
Try it!
-Demo Server (Location: Frankfurt - Germany): https://demo.kuma.pet/start-demo
+Demo Server (Location: Frankfurt - Germany):
It is a temporary live demo, all data will be deleted after 10 minutes. Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors).
@@ -37,35 +37,44 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Sponsore
## 🔧 How to Install
-### 🐳 Docker
+### 🐳 Docker Compose
```bash
-docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
+mkdir uptime-kuma
+cd uptime-kuma
+curl -o compose.yaml https://raw.githubusercontent.com/louislam/uptime-kuma/master/compose.yaml
+docker compose up -d
```
-
-Uptime Kuma is now running on .
+Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
> [!WARNING]
> File Systems like **NFS** (Network File System) are **NOT** supported. Please map to a local directory or volume.
-> [!NOTE]
-> If you want to limit exposure to localhost (without exposing port for other users or to use a [reverse proxy](https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy)), you can expose the port like this:
->
-> ```bash
-> docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
-> ```
+### 🐳 Docker Command
+
+```bash
+docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2
+```
+Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
+
+If you want to limit exposure to localhost only:
+
+```bash
+docker run ... -p 127.0.0.1:3001:3001 ...
+```
+
+
### 💪🏻 Non-Docker
Requirements:
- Platform
- - ✅ Major Linux distros such as Debian, Ubuntu, CentOS, Fedora and ArchLinux etc.
+ - ✅ Major Linux distros such as Debian, Ubuntu, Fedora and ArchLinux etc.
- ✅ Windows 10 (x64), Windows Server 2012 R2 (x64) or higher
- ❌ FreeBSD / OpenBSD / NetBSD
- ❌ Replit / Heroku
-- [Node.js](https://nodejs.org/en/download/) 18 / 20.4
-- [npm](https://docs.npmjs.com/cli/) 9
+- [Node.js](https://nodejs.org/en/download/) >= 20.4
- [Git](https://git-scm.com/downloads)
- [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background
@@ -84,8 +93,7 @@ npm install pm2 -g && pm2 install pm2-logrotate
# Start Server
pm2 start server/server.js --name uptime-kuma
```
-
-Uptime Kuma is now running on http://localhost:3001
+Uptime Kuma is now running on all network interfaces (e.g. http://localhost:3001 or http://your-ip:3001).
More useful PM2 Commands
@@ -94,26 +102,26 @@ More useful PM2 Commands
pm2 monit
# If you want to add it to startup
-pm2 save && pm2 startup
+pm2 startup && pm2 save
```
### Advanced Installation
If you need more options or need to browse via a reverse proxy, please read:
-https://github.com/louislam/uptime-kuma/wiki/%F0%9F%94%A7-How-to-Install
+
## 🆙 How to Update
Please read:
-https://github.com/louislam/uptime-kuma/wiki/%F0%9F%86%99-How-to-Update
+
## 🆕 What's Next?
I will assign requests/issues to the next milestone.
-https://github.com/louislam/uptime-kuma/milestones
+
## ❤️ Sponsors
@@ -174,11 +182,11 @@ We DO NOT accept all types of pull requests and do not want to waste your time.
There are a lot of pull requests right now, but I don't have time to test them all.
If you want to help, you can check this:
-https://github.com/louislam/uptime-kuma/wiki/Test-Pull-Requests
+
### Test Beta Version
-Check out the latest beta release here: https://github.com/louislam/uptime-kuma/releases
+Check out the latest beta release here:
### Bug Reports / Feature Requests
@@ -192,5 +200,3 @@ If you want to translate Uptime Kuma into your language, please visit [Weblate R
Feel free to correct the grammar in the documentation or code.
My mother language is not English and my grammar is not that great.
-
-
diff --git a/SECURITY.md b/SECURITY.md
index a7de9e997..34111c258 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -8,7 +8,8 @@
do not send a notification, I probably will miss it without this.
-Do not use the public issue tracker or discuss it in public as it will cause
+- Do not report any upstream dependency issues / scan result by any tools. It will be closed immediately without explanations. Unless you have PoC to prove that the upstream issue affected Uptime Kuma.
+- Do not use the public issue tracker or discuss it in public as it will cause
more damage.
## Do you accept other 3rd-party bug bounty platforms?
@@ -22,17 +23,21 @@ Advisories only. I will ignore all 3rd-party bug bounty platforms emails.
### Uptime Kuma Versions
-You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X`
-versions are upgradable to the latest version.
+You should use or upgrade to the latest version of Uptime Kuma.
+All versions are upgradable to the latest version.
### Upgradable Docker Tags
-| Tag | Supported |
-| -------------- | ------------------ |
-| 1 | :white_check_mark: |
-| 1-debian | :white_check_mark: |
-| latest | :white_check_mark: |
-| debian | :white_check_mark: |
-| 1-alpine | ⚠️ Deprecated |
-| alpine | ⚠️ Deprecated |
-| All other tags | ❌ |
+| Tag | Supported |
+| --------------- | ------------------------------------------------------------------------------------- |
+| 2 | :white_check_mark: |
+| 2-slim | :white_check_mark: |
+| next | :white_check_mark: |
+| next-slim | :white_check_mark: |
+| 2-rootless | :white_check_mark: |
+| 2-slim-rootless | :white_check_mark: |
+| 1 | [⚠️ Deprecated](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) |
+| 1-debian | [⚠️ Deprecated](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) |
+| latest | [⚠️ Deprecated](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) |
+| debian | [⚠️ Deprecated](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) |
+| All other tags | ❌ |
diff --git a/compose.yaml b/compose.yaml
index 004705a63..914e8603d 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -1,9 +1,9 @@
services:
uptime-kuma:
- image: louislam/uptime-kuma:1
+ image: louislam/uptime-kuma:2
+ restart: unless-stopped
volumes:
- ./data:/app/data
ports:
# :
- - 3001:3001
- restart: unless-stopped
+ - "3001:3001"
diff --git a/config/vite.config.js b/config/vite.config.js
index 7f2dfb6ff..f4a60da9d 100644
--- a/config/vite.config.js
+++ b/config/vite.config.js
@@ -2,7 +2,7 @@ import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
import visualizer from "rollup-plugin-visualizer";
import viteCompression from "vite-plugin-compression";
-import VueDevTools from "vite-plugin-vue-devtools";
+import { VitePWA } from "vite-plugin-pwa";
const postCssScss = require("postcss-scss");
const postcssRTLCSS = require("postcss-rtlcss");
@@ -31,7 +31,12 @@ export default defineConfig({
algorithm: "brotliCompress",
filter: viteCompressionFilter,
}),
- VueDevTools(),
+ VitePWA({
+ registerType: null,
+ srcDir: "src",
+ filename: "serviceWorker.ts",
+ strategies: "injectManifest",
+ }),
],
css: {
postcss: {
diff --git a/db/knex_migrations/2025-01-01-0000-add-smtp.js b/db/knex_migrations/2025-01-01-0000-add-smtp.js
new file mode 100644
index 000000000..00d4835f5
--- /dev/null
+++ b/db/knex_migrations/2025-01-01-0000-add-smtp.js
@@ -0,0 +1,12 @@
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.string("smtp_security").defaultTo(null);
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("monitor", function (table) {
+ table.dropColumn("smtp_security");
+ });
+};
diff --git a/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js
new file mode 100644
index 000000000..e8bd03e53
--- /dev/null
+++ b/db/knex_migrations/2025-03-04-0000-ping-advanced-options.js
@@ -0,0 +1,24 @@
+/* SQL:
+ALTER TABLE monitor ADD ping_count INTEGER default 1 not null;
+ALTER TABLE monitor ADD ping_numeric BOOLEAN default true not null;
+ALTER TABLE monitor ADD ping_per_request_timeout INTEGER default 2 not null;
+*/
+exports.up = function (knex) {
+ // Add new columns to table monitor
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.integer("ping_count").defaultTo(1).notNullable();
+ table.boolean("ping_numeric").defaultTo(true).notNullable();
+ table.integer("ping_per_request_timeout").defaultTo(2).notNullable();
+ });
+
+};
+
+exports.down = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.dropColumn("ping_count");
+ table.dropColumn("ping_numeric");
+ table.dropColumn("ping_per_request_timeout");
+ });
+};
diff --git a/db/knex_migrations/2025-05-09-0000-add-custom-url.js b/db/knex_migrations/2025-05-09-0000-add-custom-url.js
new file mode 100644
index 000000000..b3465c87f
--- /dev/null
+++ b/db/knex_migrations/2025-05-09-0000-add-custom-url.js
@@ -0,0 +1,13 @@
+// Add column custom_url to monitor_group table
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor_group", function (table) {
+ table.text("custom_url", "text");
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("monitor_group", function (table) {
+ table.dropColumn("custom_url");
+ });
+};
diff --git a/db/knex_migrations/2025-06-03-0000-add-ip-family.js b/db/knex_migrations/2025-06-03-0000-add-ip-family.js
new file mode 100644
index 000000000..a3bcdc613
--- /dev/null
+++ b/db/knex_migrations/2025-06-03-0000-add-ip-family.js
@@ -0,0 +1,13 @@
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.boolean("ip_family").defaultTo(null);
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.dropColumn("ip_family");
+ });
+};
diff --git a/db/knex_migrations/2025-06-11-0000-add-manual-monitor.js b/db/knex_migrations/2025-06-11-0000-add-manual-monitor.js
new file mode 100644
index 000000000..16d307eb5
--- /dev/null
+++ b/db/knex_migrations/2025-06-11-0000-add-manual-monitor.js
@@ -0,0 +1,12 @@
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.string("manual_status").defaultTo(null);
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("monitor", function (table) {
+ table.dropColumn("manual_status");
+ });
+};
diff --git a/db/knex_migrations/2025-06-13-0000-maintenance-add-last-start.js b/db/knex_migrations/2025-06-13-0000-maintenance-add-last-start.js
new file mode 100644
index 000000000..3cb28d968
--- /dev/null
+++ b/db/knex_migrations/2025-06-13-0000-maintenance-add-last-start.js
@@ -0,0 +1,34 @@
+// Add column last_start_date to maintenance table
+exports.up = async function (knex) {
+ await knex.schema
+ .alterTable("maintenance", function (table) {
+ table.datetime("last_start_date");
+ });
+
+ // Perform migration for recurring-interval strategy
+ const recurringMaintenances = await knex("maintenance").where({
+ strategy: "recurring-interval",
+ cron: "* * * * *"
+ }).select("id", "start_time");
+
+ // eslint-disable-next-line camelcase
+ const maintenanceUpdates = recurringMaintenances.map(async ({ start_time, id }) => {
+ // eslint-disable-next-line camelcase
+ const [ hourStr, minuteStr ] = start_time.split(":");
+ const hour = parseInt(hourStr, 10);
+ const minute = parseInt(minuteStr, 10);
+
+ const cron = `${minute} ${hour} * * *`;
+
+ await knex("maintenance")
+ .where({ id })
+ .update({ cron });
+ });
+ await Promise.all(maintenanceUpdates);
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("maintenance", function (table) {
+ table.dropColumn("last_start_date");
+ });
+};
diff --git a/db/knex_migrations/2025-06-15-0001-manual-monitor-fix.js b/db/knex_migrations/2025-06-15-0001-manual-monitor-fix.js
new file mode 100644
index 000000000..b05c1131e
--- /dev/null
+++ b/db/knex_migrations/2025-06-15-0001-manual-monitor-fix.js
@@ -0,0 +1,13 @@
+// Fix: Change manual_status column type to smallint
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.smallint("manual_status").alter();
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("monitor", function (table) {
+ table.string("manual_status").alter();
+ });
+};
diff --git a/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js b/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js
new file mode 100644
index 000000000..6666ed9c8
--- /dev/null
+++ b/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js
@@ -0,0 +1,12 @@
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.string("oauth_audience").nullable().defaultTo(null);
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema.alterTable("monitor", function (table) {
+ table.string("oauth_audience").alter();
+ });
+};
diff --git a/db/knex_migrations/2025-07-17-0000-mqtt-websocket-path.js b/db/knex_migrations/2025-07-17-0000-mqtt-websocket-path.js
new file mode 100644
index 000000000..85b05f110
--- /dev/null
+++ b/db/knex_migrations/2025-07-17-0000-mqtt-websocket-path.js
@@ -0,0 +1,15 @@
+exports.up = function (knex) {
+ // Add new column monitor.mqtt_websocket_path
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.string("mqtt_websocket_path", 255).nullable();
+ });
+};
+
+exports.down = function (knex) {
+ // Drop column monitor.mqtt_websocket_path
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ table.dropColumn("mqtt_websocket_path");
+ });
+};
diff --git a/db/knex_migrations/2025-10-14-0000-add-ip-family-fix.js b/db/knex_migrations/2025-10-14-0000-add-ip-family-fix.js
new file mode 100644
index 000000000..5c9c3845f
--- /dev/null
+++ b/db/knex_migrations/2025-10-14-0000-add-ip-family-fix.js
@@ -0,0 +1,16 @@
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ // Fix ip_family, change to varchar instead of boolean
+ // possible values are "ipv4" and "ipv6"
+ table.string("ip_family", 4).defaultTo(null).alter();
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema
+ .alterTable("monitor", function (table) {
+ // Rollback to boolean
+ table.boolean("ip_family").defaultTo(null).alter();
+ });
+};
diff --git a/db/knex_migrations/2025-10-15-0000-stat-table-fix.js b/db/knex_migrations/2025-10-15-0000-stat-table-fix.js
new file mode 100644
index 000000000..7c3038692
--- /dev/null
+++ b/db/knex_migrations/2025-10-15-0000-stat-table-fix.js
@@ -0,0 +1,27 @@
+// Fix for #4315. Logically, setting it to 0 ping may not be correct, but it is better than throwing errors
+
+exports.up = function (knex) {
+ return knex.schema
+ .alterTable("stat_daily", function (table) {
+ table.integer("ping").defaultTo(0).alter();
+ })
+ .alterTable("stat_hourly", function (table) {
+ table.integer("ping").defaultTo(0).alter();
+ })
+ .alterTable("stat_minutely", function (table) {
+ table.integer("ping").defaultTo(0).alter();
+ });
+};
+
+exports.down = function (knex) {
+ return knex.schema
+ .alterTable("stat_daily", function (table) {
+ table.integer("ping").alter();
+ })
+ .alterTable("stat_hourly", function (table) {
+ table.integer("ping").alter();
+ })
+ .alterTable("stat_minutely", function (table) {
+ table.integer("ping").alter();
+ });
+};
diff --git a/db/knex_migrations/2025-10-24-0000-show-only-last-heartbeat.js b/db/knex_migrations/2025-10-24-0000-show-only-last-heartbeat.js
new file mode 100644
index 000000000..75d6fb77e
--- /dev/null
+++ b/db/knex_migrations/2025-10-24-0000-show-only-last-heartbeat.js
@@ -0,0 +1,15 @@
+exports.up = function (knex) {
+ // Add new column status_page.show_only_last_heartbeat
+ return knex.schema
+ .alterTable("status_page", function (table) {
+ table.boolean("show_only_last_heartbeat").notNullable().defaultTo(false);
+ });
+};
+
+exports.down = function (knex) {
+ // Drop column status_page.show_only_last_heartbeat
+ return knex.schema
+ .alterTable("status_page", function (table) {
+ table.dropColumn("show_only_last_heartbeat");
+ });
+};
diff --git a/docker/builder-go.dockerfile b/docker/builder-go.dockerfile
index 1d25843bc..3a9d78248 100644
--- a/docker/builder-go.dockerfile
+++ b/docker/builder-go.dockerfile
@@ -2,11 +2,17 @@
# Build in Golang
# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck
############################################
-FROM golang:1.19-buster
+FROM golang:1-buster
WORKDIR /app
ARG TARGETPLATFORM
COPY ./extra/ ./extra/
+## Switch to archive.debian.org
+RUN sed -i '/^deb/s/^/#/' /etc/apt/sources.list \
+ && echo "deb http://archive.debian.org/debian buster main contrib non-free" | tee -a /etc/apt/sources.list \
+ && echo "deb http://archive.debian.org/debian-security buster/updates main contrib non-free" | tee -a /etc/apt/sources.list \
+ && echo "deb http://archive.debian.org/debian buster-updates main contrib non-free" | tee -a /etc/apt/sources.list
+
# Compile healthcheck.go
RUN apt update && \
apt --yes --no-install-recommends install curl && \
diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile
index a17174371..10471af2a 100644
--- a/docker/debian-base.dockerfile
+++ b/docker/debian-base.dockerfile
@@ -1,5 +1,5 @@
# Download Apprise deb package
-FROM node:20-bookworm-slim AS download-apprise
+FROM node:22-bookworm-slim AS download-apprise
WORKDIR /app
COPY ./extra/download-apprise.mjs ./download-apprise.mjs
RUN apt update && \
@@ -9,7 +9,7 @@ RUN apt update && \
# Base Image (Slim)
# If the image changed, the second stage image should be changed too
-FROM node:20-bookworm-slim AS base2-slim
+FROM node:22-bookworm-slim AS base2-slim
ARG TARGETPLATFORM
# Specify --no-install-recommends to skip unused dependencies, make the base much smaller!
@@ -47,9 +47,9 @@ RUN apt update && \
# Install cloudflared
RUN curl https://pkg.cloudflare.com/cloudflare-main.gpg --output /usr/share/keyrings/cloudflare-main.gpg && \
- echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bullseye main' | tee /etc/apt/sources.list.d/cloudflared.list && \
+ echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bookworm main' | tee /etc/apt/sources.list.d/cloudflared.list && \
apt update && \
- apt install --yes --no-install-recommends -t stable cloudflared && \
+ apt install --yes --no-install-recommends cloudflared && \
cloudflared version && \
rm -rf /var/lib/apt/lists/* && \
apt --yes autoremove
diff --git a/docker/dockerfile b/docker/dockerfile
index d55f94f61..e2a301e7b 100644
--- a/docker/dockerfile
+++ b/docker/dockerfile
@@ -79,6 +79,10 @@ USER node
RUN git config --global user.email "no-reply@no-reply.com"
RUN git config --global user.name "PR Tester"
RUN git clone https://github.com/louislam/uptime-kuma.git .
+
+# Hide the warning when running in detached head state
+RUN git config --global advice.detachedHead false
+
RUN npm ci
EXPOSE 3000 3001
diff --git a/extra/beta/update-version.js b/extra/beta/update-version.js
index 9ab00155b..4af645e0e 100644
--- a/extra/beta/update-version.js
+++ b/extra/beta/update-version.js
@@ -24,9 +24,7 @@ if (! exists) {
// Also update package-lock.json
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
childProcess.spawnSync(npm, [ "install" ]);
-
commit(version);
- tag(version);
} else {
console.log("version tag exists, please delete the tag or use another tag");
@@ -54,19 +52,6 @@ function commit(version) {
console.log(res.stdout.toString().trim());
}
-/**
- * Create a tag with the specified version
- * @param {string} version Tag to create
- * @returns {void}
- */
-function tag(version) {
- let res = childProcess.spawnSync("git", [ "tag", version ]);
- console.log(res.stdout.toString().trim());
-
- res = childProcess.spawnSync("git", [ "push", "origin", version ]);
- console.log(res.stdout.toString().trim());
-}
-
/**
* Check if a tag exists for the specified version
* @param {string} version Version to check
diff --git a/extra/checkout-pr.js b/extra/checkout-pr.js
deleted file mode 100644
index 0328770b1..000000000
--- a/extra/checkout-pr.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const childProcess = require("child_process");
-
-if (!process.env.UPTIME_KUMA_GH_REPO) {
- console.error("Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
- process.exit(1);
-}
-
-let inputArray = process.env.UPTIME_KUMA_GH_REPO.split(":");
-
-if (inputArray.length !== 2) {
- console.error("Invalid format. Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
-}
-
-let name = inputArray[0];
-let branch = inputArray[1];
-
-console.log("Checkout pr");
-
-// Checkout the pr
-let result = childProcess.spawnSync("git", [ "remote", "add", name, `https://github.com/${name}/uptime-kuma` ]);
-
-console.log(result.stdout.toString());
-console.error(result.stderr.toString());
-
-result = childProcess.spawnSync("git", [ "fetch", name, branch ]);
-
-console.log(result.stdout.toString());
-console.error(result.stderr.toString());
-
-result = childProcess.spawnSync("git", [ "checkout", `${name}/${branch}`, "--force" ]);
-
-console.log(result.stdout.toString());
-console.error(result.stderr.toString());
diff --git a/extra/checkout-pr.mjs b/extra/checkout-pr.mjs
new file mode 100644
index 000000000..653664477
--- /dev/null
+++ b/extra/checkout-pr.mjs
@@ -0,0 +1,34 @@
+import childProcess from "child_process";
+import { parsePrName } from "./kuma-pr/pr-lib.mjs";
+
+let { name, branch } = parsePrName(process.env.UPTIME_KUMA_GH_REPO);
+
+console.log(`Checking out PR from ${name}:${branch}`);
+
+// Checkout the pr
+let result = childProcess.spawnSync("git", [ "remote", "add", name, `https://github.com/${name}/uptime-kuma` ], {
+ stdio: "inherit"
+});
+
+if (result.status !== 0) {
+ console.error("Failed to add remote repository.");
+ process.exit(1);
+}
+
+result = childProcess.spawnSync("git", [ "fetch", name, branch ], {
+ stdio: "inherit"
+});
+
+if (result.status !== 0) {
+ console.error("Failed to fetch the branch.");
+ process.exit(1);
+}
+
+result = childProcess.spawnSync("git", [ "checkout", `${name}/${branch}`, "--force" ], {
+ stdio: "inherit"
+});
+
+if (result.status !== 0) {
+ console.error("Failed to checkout the branch.");
+ process.exit(1);
+}
diff --git a/extra/close-incorrect-issue.js b/extra/close-incorrect-issue.js
index 9bb01b19d..33a35f805 100644
--- a/extra/close-incorrect-issue.js
+++ b/extra/close-incorrect-issue.js
@@ -37,7 +37,7 @@ const github = require("@actions/github");
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
- body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please **DO NOT open blank issues and use our [issue-templates](https://github.com/louislam/uptime-kuma/issues/new/choose) instead**.\nBlank Issues do not contain the context nessesary for a good discussions.`
+ body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please **DO NOT open blank issues and use our [issue-templates](https://github.com/louislam/uptime-kuma/issues/new/choose) instead**.\nBlank Issues do not contain the context necessary for a good discussions.`
});
// Close the issue
diff --git a/extra/generate-changelog.mjs b/extra/generate-changelog.mjs
new file mode 100644
index 000000000..2d269836b
--- /dev/null
+++ b/extra/generate-changelog.mjs
@@ -0,0 +1,201 @@
+// Script to generate changelog
+// Usage: node generate-changelog.mjs
+// GitHub CLI (gh command) is required
+
+import * as childProcess from "child_process";
+
+const ignoreList = [
+ "louislam",
+ "CommanderStorm",
+ "UptimeKumaBot",
+ "weblate",
+ "Copilot"
+];
+
+const mergeList = [
+ "Translations Update from Weblate",
+ "Update dependencies",
+];
+
+const template = `
+
+LLM Task: Please help to put above PRs into the following sections based on their content. If a PR fits multiple sections, choose the most relevant one. If a PR doesn't fit any section, place it in "Others". If there are grammatical errors in the PR titles, please correct them. Don't change the PR numbers and authors, and keep the format. Output as markdown.
+
+Changelog:
+
+### 🆕 New Features
+
+### 💇♀️ Improvements
+
+### 🐞 Bug Fixes
+
+### ⬆️ Security Fixes
+
+### 🦎 Translation Contributions
+
+### Others
+- Other small changes, code refactoring and comment/doc updates in this repo:
+`;
+
+await main();
+
+/**
+ * Main Function
+ * @returns {Promise}
+ */
+async function main() {
+ const previousVersion = process.argv[2];
+
+ if (!previousVersion) {
+ console.error("Please provide the previous version as the first argument.");
+ process.exit(1);
+ }
+
+ console.log(`Generating changelog since version ${previousVersion}...`);
+
+ try {
+ const prList = await getPullRequestList(previousVersion);
+ const list = [];
+
+ let i = 1;
+ for (const pr of prList) {
+ console.log(`Progress: ${i++}/${prList.length}`);
+ let authorSet = await getAuthorList(pr.number);
+ authorSet = await mainAuthorToFront(pr.author.login, authorSet);
+
+ if (mergeList.includes(pr.title)) {
+ // Check if it is already in the list
+ const existingItem = list.find(item => item.title === pr.title);
+ if (existingItem) {
+ existingItem.numbers.push(pr.number);
+ for (const author of authorSet) {
+ existingItem.authors.add(author);
+ // Sort the authors
+ existingItem.authors = new Set([ ...existingItem.authors ].sort((a, b) => a.localeCompare(b)));
+ }
+ continue;
+ }
+ }
+
+ const item = {
+ numbers: [ pr.number ],
+ title: pr.title,
+ authors: authorSet,
+ };
+
+ list.push(item);
+ }
+
+ for (const item of list) {
+ // Concat pr numbers into a string like #123 #456
+ const prPart = item.numbers.map(num => `#${num}`).join(" ");
+
+ // Concat authors into a string like @user1 @user2
+ let authorPart = [ ...item.authors ].map(author => `@${author}`).join(" ");
+
+ if (authorPart) {
+ authorPart = `(Thanks ${authorPart})`;
+ }
+
+ console.log(`- ${prPart} ${item.title} ${authorPart}`);
+ }
+
+ console.log(template);
+
+ } catch (e) {
+ console.error("Failed to get pull request list:", e);
+ process.exit(1);
+ }
+}
+
+/**
+ * @param {string} previousVersion Previous Version Tag
+ * @returns {Promise