Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b4bb6b33a | |||
| e16b492257 | |||
| 265e02119a | |||
| 82d454ade4 | |||
| a9b300d711 | |||
| fded3a04d4 | |||
| 0d897f17b5 | |||
| 216f6f83fe | |||
| c023bdccae | |||
| 78f3ad8fcc | |||
| 2e7a52ed15 | |||
| 221b3533e5 | |||
| 578dccd0cf | |||
| 0ecad475ef | |||
| d5789b79a6 | |||
| 45ce90f3cc | |||
| 3a817625c5 | |||
| d5abea48b3 | |||
| 1da69ac272 | |||
| bd2092a3ea | |||
| afb6fb8ac7 | |||
| 414e9f4c33 | |||
| 10035221fb | |||
| 52a6f4368c | |||
| e774dbc301 | |||
| 5bf582f3ad |
@@ -0,0 +1,92 @@
|
|||||||
|
name: PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: https://git.keligrubb.com/actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: https://git.keligrubb.com/actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: npm run test
|
||||||
|
|
||||||
|
e2e:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: mcr.microsoft.com/playwright:v1.59.1-noble
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: https://git.keligrubb.com/actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Generate dev cert
|
||||||
|
run: ./scripts/gen-dev-cert.sh
|
||||||
|
|
||||||
|
- name: Run e2e tests
|
||||||
|
run: npm run test:e2e
|
||||||
|
env:
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Set Docker image tag
|
||||||
|
id: image
|
||||||
|
run: |
|
||||||
|
REGISTRY="${GITHUB_SERVER_URL#https://}"
|
||||||
|
REGISTRY="${REGISTRY#http://}"
|
||||||
|
echo "tag=${REGISTRY}/${{ github.repository }}:latest" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: https://git.keligrubb.com/actions/docker-setup-buildx-action@v4
|
||||||
|
|
||||||
|
- name: Build (dry run)
|
||||||
|
uses: https://git.keligrubb.com/actions/docker-build-push-action@v7
|
||||||
|
env:
|
||||||
|
# Keeps GITHUB_OUTPUT small; Gitea act-runner can choke on multiline
|
||||||
|
# outputs when PR webhook payloads (e.g. Renovate bodies) are huge.
|
||||||
|
DOCKER_BUILD_SUMMARY: "false"
|
||||||
|
DOCKER_BUILD_RECORD_UPLOAD: "false"
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: false
|
||||||
|
provenance: false
|
||||||
|
sbom: false
|
||||||
|
tags: ${{ steps.image.outputs.tag }}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
name: Push
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get PR description for changelog
|
||||||
|
env:
|
||||||
|
GITEA_REPO_TOKEN: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
run: |
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/microsoft*.list /etc/apt/sources.list.d/azure*.list 2>/dev/null || true
|
||||||
|
sudo apt-get update -qq && sudo apt-get install -y -qq jq
|
||||||
|
RESP=$(curl -sf -H "Authorization: token $GITEA_REPO_TOKEN" \
|
||||||
|
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/commits/${{ github.sha }}/pull") || true
|
||||||
|
if [ -n "$RESP" ]; then
|
||||||
|
echo "$RESP" | jq -r '.body // empty' > .ci_pr_body 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Release (bump, tag, push, create release)
|
||||||
|
env:
|
||||||
|
CI_REPO_OWNER: ${{ github.actor }}
|
||||||
|
CI_REPO_NAME: ${{ github.event.repository.name }}
|
||||||
|
CI_FORGE_URL: ${{ github.server_url }}
|
||||||
|
CI_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
GITEA_REPO_TOKEN: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
run: |
|
||||||
|
sudo rm -f /etc/apt/sources.list.d/microsoft*.list /etc/apt/sources.list.d/azure*.list 2>/dev/null || true
|
||||||
|
sudo apt-get update -qq && sudo apt-get install -y -qq git wget
|
||||||
|
./scripts/release.sh
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://git.keligrubb.com/actions/checkout@v6
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
token: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
|
||||||
|
- name: Log in to container registry
|
||||||
|
uses: https://git.keligrubb.com/actions/docker-login-action@v4
|
||||||
|
with:
|
||||||
|
registry: git.keligrubb.com
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: https://git.keligrubb.com/actions/docker-setup-buildx-action@v4
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: https://git.keligrubb.com/actions/docker-build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
load: true
|
||||||
|
tags: kestrelos:built
|
||||||
|
|
||||||
|
- name: Push Docker image (version + latest)
|
||||||
|
run: |
|
||||||
|
VERSION=$(awk '/"version"/ { match($0, /[0-9]+\.[0-9]+\.[0-9]+/); print substr($0, RSTART, RLENGTH); exit }' package.json)
|
||||||
|
case "$VERSION" in
|
||||||
|
[0-9]*.[0-9]*.[0-9]*) ;;
|
||||||
|
*) echo "error: package.json version must be x.y.z (got: $VERSION)"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
REGISTRY="git.keligrubb.com"
|
||||||
|
IMAGE="$REGISTRY/${{ github.repository }}"
|
||||||
|
for tag in "$VERSION" latest; do
|
||||||
|
docker tag kestrelos:built "$IMAGE:$tag"
|
||||||
|
docker push "$IMAGE:$tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: https://git.keligrubb.com/actions/setup-helm@v5
|
||||||
|
|
||||||
|
- name: Package and push Helm chart
|
||||||
|
env:
|
||||||
|
GITEA_REPO_TOKEN: ${{ secrets.KESTRELOS_REPO_TOKEN }}
|
||||||
|
run: |
|
||||||
|
helm package helm/kestrelos
|
||||||
|
for f in kestrelos-*.tgz; do
|
||||||
|
curl -sf -u "${{ github.actor }}:$GITEA_REPO_TOKEN" -X POST --upload-file "$f" \
|
||||||
|
"${{ github.server_url }}/api/packages/${{ github.actor }}/helm/api/charts"
|
||||||
|
done
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
when:
|
|
||||||
- event: pull_request
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: install
|
|
||||||
image: node:24-slim
|
|
||||||
depends_on: []
|
|
||||||
commands:
|
|
||||||
- npm ci
|
|
||||||
|
|
||||||
- name: lint
|
|
||||||
image: node:24-slim
|
|
||||||
depends_on: [install]
|
|
||||||
commands:
|
|
||||||
- npm run lint
|
|
||||||
|
|
||||||
- name: test
|
|
||||||
image: node:24-slim
|
|
||||||
depends_on: [install]
|
|
||||||
commands:
|
|
||||||
- npm run test
|
|
||||||
|
|
||||||
- name: e2e
|
|
||||||
image: mcr.microsoft.com/playwright:v1.58.2-noble
|
|
||||||
depends_on: [install]
|
|
||||||
commands:
|
|
||||||
- ./scripts/gen-dev-cert.sh
|
|
||||||
- npm run test:e2e
|
|
||||||
environment:
|
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
|
||||||
|
|
||||||
- name: docker-build
|
|
||||||
image: woodpeckerci/plugin-kaniko
|
|
||||||
depends_on: []
|
|
||||||
settings:
|
|
||||||
repo: ${CI_REPO_OWNER}/${CI_REPO_NAME}
|
|
||||||
registry: git.keligrubb.com
|
|
||||||
tags: latest
|
|
||||||
dry-run: true
|
|
||||||
single-snapshot: true
|
|
||||||
cleanup: true
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
when:
|
|
||||||
- event: push
|
|
||||||
branch: main
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: release
|
|
||||||
image: alpine
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache git
|
|
||||||
- ./scripts/release.sh
|
|
||||||
environment:
|
|
||||||
GITEA_REPO_TOKEN:
|
|
||||||
from_secret: gitea_repo_token
|
|
||||||
|
|
||||||
- name: docker
|
|
||||||
image: woodpeckerci/plugin-kaniko
|
|
||||||
depends_on: [release]
|
|
||||||
settings:
|
|
||||||
repo: ${CI_REPO_OWNER}/${CI_REPO_NAME}
|
|
||||||
registry: git.keligrubb.com
|
|
||||||
username: ${CI_REPO_OWNER}
|
|
||||||
password:
|
|
||||||
from_secret: gitea_registry_token
|
|
||||||
single-snapshot: true
|
|
||||||
cleanup: true
|
|
||||||
|
|
||||||
- name: helm
|
|
||||||
image: alpine/helm
|
|
||||||
depends_on: [release]
|
|
||||||
environment:
|
|
||||||
GITEA_REGISTRY_TOKEN:
|
|
||||||
from_secret: gitea_registry_token
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache curl
|
|
||||||
- helm package helm/kestrelos
|
|
||||||
- curl -sf -u $CI_REPO_OWNER:$GITEA_REGISTRY_TOKEN -X POST --upload-file kestrelos-*.tgz https://git.keligrubb.com/api/packages/$CI_REPO_OWNER/helm/api/charts
|
|
||||||
+133
@@ -1,3 +1,136 @@
|
|||||||
|
## [1.1.3] - 2026-04-19
|
||||||
|
### Changed
|
||||||
|
- update dependency mediasoup-client to v3.18.8 (#30)
|
||||||
|
|
||||||
|
This PR contains the following updates:
|
||||||
|
|
||||||
|
| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [mediasoup-client](https://mediasoup.org) ([source](https://github.com/versatica/mediasoup-client)) | [`3.18.7` → `3.18.8`](https://renovatebot.com/diffs/npm/mediasoup-client/3.18.7/3.18.8) |  |  |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Release Notes
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>versatica/mediasoup-client (mediasoup-client)</summary>
|
||||||
|
|
||||||
|
### [`v3.18.8`](https://github.com/versatica/mediasoup-client/compare/3.18.7...3.18.8)
|
||||||
|
|
||||||
|
[Compare Source](https://github.com/versatica/mediasoup-client/compare/3.18.7...3.18.8)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
|
||||||
|
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMjkuMCIsInVwZGF0ZWRJblZlciI6IjQzLjEyOS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
|
||||||
|
|
||||||
|
## [1.1.2] - 2026-04-15
|
||||||
|
### Changed
|
||||||
|
- Update dependency fast-xml-parser to v5.6.0 (#28)
|
||||||
|
|
||||||
|
This PR contains the following updates:
|
||||||
|
|
||||||
|
| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) | [`5.5.12` → `5.6.0`](https://renovatebot.com/diffs/npm/fast-xml-parser/5.5.12/5.6.0) |  |  |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Release Notes
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>NaturalIntelligence/fast-xml-parser (fast-xml-parser)</summary>
|
||||||
|
|
||||||
|
### [`v5.6.0`](https://github.com/NaturalIntelligence/fast-xml-parser/releases/tag/v5.6.0): use @​nodable/entities to replace entities
|
||||||
|
|
||||||
|
[Compare Source](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.5.12...v5.6.0)
|
||||||
|
|
||||||
|
- No API change
|
||||||
|
- No change in performance for basic usage
|
||||||
|
- No typing change
|
||||||
|
- No config change
|
||||||
|
- new dependency
|
||||||
|
- breaking: error messages for entities might have been changed.
|
||||||
|
-
|
||||||
|
|
||||||
|
**Full Changelog**: <https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.5.12...v5.6.0>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
📅 **Schedule**: (UTC)
|
||||||
|
|
||||||
|
- Branch creation
|
||||||
|
- At any time (no schedule defined)
|
||||||
|
- Automerge
|
||||||
|
- At any time (no schedule defined)
|
||||||
|
|
||||||
|
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
|
||||||
|
|
||||||
|
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
|
||||||
|
|
||||||
|
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
|
||||||
|
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMjAuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEyMC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
|
||||||
|
|
||||||
|
## [1.1.1] - 2026-04-15
|
||||||
|
### Changed
|
||||||
|
- split push release/publish and harden workflows (#27)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Separate release from Docker/Helm publish
|
||||||
|
* enrich releases with PRbodies when available
|
||||||
|
* tighten release.sh validation and idempotency
|
||||||
|
* trim PR docker-build metadata for act-runner stability
|
||||||
|
|
||||||
|
## [1.1.0] - 2026-04-15
|
||||||
|
### Changed
|
||||||
|
- Update all non-major dependencies (#25)
|
||||||
|
|
||||||
|
## [1.0.10] - 2026-04-15
|
||||||
|
### Changed
|
||||||
|
- Remove npm overrides for tar (#26)
|
||||||
|
|
||||||
|
## [1.0.9] - 2026-03-24
|
||||||
|
### Changed
|
||||||
|
- update https://git.keligrubb.com/actions/setup-helm action to v5 (#23)
|
||||||
|
|
||||||
|
## [1.0.8] - 2026-03-12
|
||||||
|
### Changed
|
||||||
|
- fix release file (#22)
|
||||||
|
|
||||||
|
## [1.0.7] - 2026-03-06
|
||||||
|
### Changed
|
||||||
|
- chore(deps): update docker/build-push-action action to v7 (#19)
|
||||||
|
|
||||||
|
## [1.0.6] - 2026-03-05
|
||||||
|
### Changed
|
||||||
|
- fix docker login during push stage (#18)
|
||||||
|
|
||||||
|
## [1.0.5] - 2026-03-05
|
||||||
|
### Changed
|
||||||
|
- fix deploy pipeline stages for token registry uploads (#17)
|
||||||
|
|
||||||
|
## [1.0.4] - 2026-03-04
|
||||||
|
### Changed
|
||||||
|
- fix deploy pipeline (#15)
|
||||||
|
|
||||||
|
## [1.0.3] - 2026-02-23
|
||||||
|
### Changed
|
||||||
|
- fix(deps): update dependency vue-router to v5 (#12)
|
||||||
|
|
||||||
## [1.0.2] - 2026-02-22
|
## [1.0.2] - 2026-02-22
|
||||||
### Changed
|
### Changed
|
||||||
- chore(deps): update dependency eslint to v10 (#10)
|
- chore(deps): update dependency eslint to v10 (#10)
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: kestrelos
|
name: kestrelos
|
||||||
description: KestrelOS TOC for OSINT feeds - map, camera feeds, offline tiles
|
description: KestrelOS TOC for OSINT feeds - map, camera feeds, offline tiles
|
||||||
type: application
|
type: application
|
||||||
version: 1.0.2
|
version: 1.1.3
|
||||||
appVersion: "1.0.2"
|
appVersion: "1.1.3"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ replicaCount: 1
|
|||||||
|
|
||||||
image:
|
image:
|
||||||
repository: git.keligrubb.com/keligrubb/kestrelos
|
repository: git.keligrubb.com/keligrubb/kestrelos
|
||||||
tag: 1.0.2
|
tag: 1.1.3
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
service:
|
service:
|
||||||
|
|||||||
Generated
+2773
-3945
File diff suppressed because it is too large
Load Diff
+2
-6
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kestrelos",
|
"name": "kestrelos",
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -31,9 +31,8 @@
|
|||||||
"nuxt": "^4.0.0",
|
"nuxt": "^4.0.0",
|
||||||
"openid-client": "^6.8.2",
|
"openid-client": "^6.8.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"sqlite3": "^5.1.7",
|
|
||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"vue-router": "^4.4.0",
|
"vue-router": "^5.0.0",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -46,8 +45,5 @@
|
|||||||
"eslint": "^10.0.0",
|
"eslint": "^10.0.0",
|
||||||
"happy-dom": "^20.6.1",
|
"happy-dom": "^20.6.1",
|
||||||
"vitest": "^4.0.0"
|
"vitest": "^4.0.0"
|
||||||
},
|
|
||||||
"overrides": {
|
|
||||||
"tar": "^7.5.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-9
@@ -3,18 +3,51 @@ set -e
|
|||||||
|
|
||||||
# version
|
# version
|
||||||
msg="${CI_COMMIT_MESSAGE:-}"
|
msg="${CI_COMMIT_MESSAGE:-}"
|
||||||
|
# optional PR body (written by workflow from Gitea API when this commit is a merged PR)
|
||||||
|
if [ -f .ci_pr_body ]; then
|
||||||
|
CI_PR_DESCRIPTION=$(cat .ci_pr_body); rm -f .ci_pr_body
|
||||||
|
else
|
||||||
|
CI_PR_DESCRIPTION=""
|
||||||
|
fi
|
||||||
|
export CI_PR_DESCRIPTION
|
||||||
bump=patch
|
bump=patch
|
||||||
echo "$msg" | grep -qi minor: && bump=minor
|
# Conventional commits: chore/fix => patch, feat => minor
|
||||||
|
echo "$msg" | grep -Eqi '(^|[[:space:]])(fix|chore)(\([^)]*\))?:' && bump=patch
|
||||||
|
echo "$msg" | grep -Eqi '(^|[[:space:]])feat(\([^)]*\))?:' && bump=minor
|
||||||
|
# Conventional commits breaking change: type!:
|
||||||
|
echo "$msg" | grep -Eqi '(^|[[:space:]])[a-zA-Z]+(\([^)]*\))?!:' && bump=major
|
||||||
|
# Explicit bump prefixes still supported (but never downgrade a major bump)
|
||||||
|
echo "$msg" | grep -qi minor: && [ "$bump" != "major" ] && bump=minor
|
||||||
echo "$msg" | grep -qi major: && bump=major
|
echo "$msg" | grep -qi major: && bump=major
|
||||||
cur=$(awk '/"version"/ { match($0, /[0-9]+\.[0-9]+\.[0-9]+/); print substr($0, RSTART, RLENGTH); exit }' package.json)
|
cur=$(awk '/"version"/ { match($0, /[0-9]+\.[0-9]+\.[0-9]+/); print substr($0, RSTART, RLENGTH); exit }' package.json)
|
||||||
|
case "$cur" in
|
||||||
|
[0-9]*.[0-9]*.[0-9]*) ;;
|
||||||
|
*) echo "error: package.json version must be x.y.z (got: $cur)"; exit 1 ;;
|
||||||
|
esac
|
||||||
major=$(echo "$cur" | cut -d. -f1); minor=$(echo "$cur" | cut -d. -f2); patch=$(echo "$cur" | cut -d. -f3)
|
major=$(echo "$cur" | cut -d. -f1); minor=$(echo "$cur" | cut -d. -f2); patch=$(echo "$cur" | cut -d. -f3)
|
||||||
case "$bump" in major) major=$((major+1)); minor=0; patch=0 ;; minor) minor=$((minor+1)); patch=0 ;; patch) patch=$((patch+1)) ;; esac
|
case "$bump" in major) major=$((major+1)); minor=0; patch=0 ;; minor) minor=$((minor+1)); patch=0 ;; patch) patch=$((patch+1)) ;; esac
|
||||||
newVersion="$major.$minor.$patch"
|
newVersion="$major.$minor.$patch"
|
||||||
[ -z "$cur" ] && { echo "error: could not read version from package.json"; exit 1; }
|
|
||||||
|
|
||||||
# changelog entry (strip prefix from first line)
|
url="https://${CI_REPO_OWNER}:${GITEA_REPO_TOKEN}@${CI_FORGE_URL#https://}/${CI_REPO_OWNER}/${CI_REPO_NAME}.git"
|
||||||
changelogEntry=$(echo "$msg" | head -1 | awk '{sub(/^[mM]ajor:[ \t]*/,""); sub(/^[mM]inor:[ \t]*/,""); sub(/^[pP]atch:[ \t]*/,""); print}')
|
if [ -n "$(git ls-remote "$url" "refs/tags/v$newVersion" 2>/dev/null)" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# changelog entry (strip explicit bump prefixes & any conventional-commit type(scope):); optional PR description enriches it
|
||||||
|
changelogEntry=$(
|
||||||
|
echo "$msg" \
|
||||||
|
| head -1 \
|
||||||
|
| sed -E 's/^[[:space:]]*[mM]ajor:[[:space:]]*//; s/^[[:space:]]*[mM]inor:[[:space:]]*//; s/^[[:space:]]*[pP]atch:[[:space:]]*//' \
|
||||||
|
| sed -E 's/^[[:space:]]*[a-zA-Z]+(\([^)]*\))?:[[:space:]]*//'
|
||||||
|
)
|
||||||
[ -z "$changelogEntry" ] && changelogEntry="Release v$newVersion"
|
[ -z "$changelogEntry" ] && changelogEntry="Release v$newVersion"
|
||||||
|
if [ -n "$CI_PR_DESCRIPTION" ]; then
|
||||||
|
changelogFull="- $changelogEntry
|
||||||
|
|
||||||
|
$CI_PR_DESCRIPTION"
|
||||||
|
else
|
||||||
|
changelogFull="- $changelogEntry"
|
||||||
|
fi
|
||||||
|
|
||||||
# bump files
|
# bump files
|
||||||
awk -v v="$newVersion" '/"version"/ { sub(/[0-9]+\.[0-9]+\.[0-9]+/, v) } { print }' package.json > package.json.tmp && mv package.json.tmp package.json
|
awk -v v="$newVersion" '/"version"/ { sub(/[0-9]+\.[0-9]+\.[0-9]+/, v) } { print }' package.json > package.json.tmp && mv package.json.tmp package.json
|
||||||
@@ -24,18 +57,18 @@ awk -v v="$newVersion" '/^ tag:/ { $0 = " tag: " v }; { print }' helm/kestrelo
|
|||||||
# changelog
|
# changelog
|
||||||
new="## [$newVersion] - $(date +%Y-%m-%d)
|
new="## [$newVersion] - $(date +%Y-%m-%d)
|
||||||
### Changed
|
### Changed
|
||||||
- $changelogEntry
|
$changelogFull
|
||||||
|
|
||||||
"
|
"
|
||||||
{ [ ! -f CHANGELOG.md ] && printf '# Changelog\n\n'; printf '%s' "$new"; [ -f CHANGELOG.md ] && cat CHANGELOG.md; } > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
|
# Create CHANGELOG.md if missing (first release); otherwise prepend new entry to existing content.
|
||||||
|
{ [ ! -f CHANGELOG.md ] && printf '# Changelog\n\n'; printf '%s' "$new"; [ -f CHANGELOG.md ] && cat CHANGELOG.md || true; } > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
|
||||||
|
|
||||||
# git
|
# git
|
||||||
git config user.email "ci@kestrelos" && git config user.name "CI"
|
git config user.email "ci@kestrelos" && git config user.name "CI"
|
||||||
git add package.json helm/kestrelos/Chart.yaml helm/kestrelos/values.yaml CHANGELOG.md
|
git add package.json helm/kestrelos/Chart.yaml helm/kestrelos/values.yaml CHANGELOG.md
|
||||||
git commit -m "release v$newVersion [skip ci]"
|
git commit -m "release v$newVersion [skip ci]"
|
||||||
url="https://${CI_REPO_OWNER}:${GITEA_REPO_TOKEN}@${CI_FORGE_URL#https://}/${CI_REPO_OWNER}/${CI_REPO_NAME}.git"
|
|
||||||
git tag "v$newVersion"
|
git tag "v$newVersion"
|
||||||
# artifact for kaniko (tag list)
|
# artifact for docker (tag list)
|
||||||
printf '%s\n%s\n' "$newVersion" "latest" > .tags
|
printf '%s\n%s\n' "$newVersion" "latest" > .tags
|
||||||
retry() { n=0; while ! "$@"; do n=$((n+1)); [ $n -ge 3 ] && return 1; sleep 2; done; }
|
retry() { n=0; while ! "$@"; do n=$((n+1)); [ $n -ge 3 ] && return 1; sleep 2; done; }
|
||||||
retry git push "$url" HEAD:main "v$newVersion"
|
retry git push "$url" HEAD:main "v$newVersion"
|
||||||
@@ -43,7 +76,7 @@ retry git push "$url" HEAD:main "v$newVersion"
|
|||||||
# gitea release
|
# gitea release
|
||||||
body="## Changelog
|
body="## Changelog
|
||||||
### Changed
|
### Changed
|
||||||
- $changelogEntry
|
$changelogFull
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
- [Docker image](${CI_FORGE_URL}/${CI_REPO_OWNER}/-/packages/container/${CI_REPO_NAME})
|
- [Docker image](${CI_FORGE_URL}/${CI_REPO_OWNER}/-/packages/container/${CI_REPO_NAME})
|
||||||
|
|||||||
+86
-24
@@ -1,14 +1,12 @@
|
|||||||
import { join, dirname } from 'node:path'
|
import { join, dirname } from 'node:path'
|
||||||
import { mkdirSync, existsSync } from 'node:fs'
|
import { mkdirSync, existsSync } from 'node:fs'
|
||||||
|
import { randomBytes, randomUUID } from 'node:crypto'
|
||||||
import { createRequire } from 'node:module'
|
import { createRequire } from 'node:module'
|
||||||
import { promisify } from 'node:util'
|
|
||||||
import { randomBytes } from 'node:crypto'
|
|
||||||
import { hashPassword } from './password.js'
|
import { hashPassword } from './password.js'
|
||||||
import { registerCleanup } from './shutdown.js'
|
import { registerCleanup } from './shutdown.js'
|
||||||
|
|
||||||
// Resolve from project root so bundled server (e.g. .output) finds node_modules/sqlite3
|
|
||||||
const requireFromRoot = createRequire(join(process.cwd(), 'package.json'))
|
const requireFromRoot = createRequire(join(process.cwd(), 'package.json'))
|
||||||
const sqlite3 = requireFromRoot('sqlite3')
|
const { DatabaseSync } = requireFromRoot('node:sqlite')
|
||||||
|
|
||||||
const SCHEMA_VERSION = 4
|
const SCHEMA_VERSION = 4
|
||||||
const DB_BUSY_TIMEOUT_MS = 5000
|
const DB_BUSY_TIMEOUT_MS = 5000
|
||||||
@@ -144,7 +142,6 @@ const initDb = async (db, run, all, get) => {
|
|||||||
catch {
|
catch {
|
||||||
// WAL not supported (e.g., network filesystem)
|
// WAL not supported (e.g., network filesystem)
|
||||||
}
|
}
|
||||||
db.configure('busyTimeout', DB_BUSY_TIMEOUT_MS)
|
|
||||||
|
|
||||||
await run(SCHEMA.schema_version)
|
await run(SCHEMA.schema_version)
|
||||||
await run(SCHEMA.users)
|
await run(SCHEMA.users)
|
||||||
@@ -168,7 +165,7 @@ const initDb = async (db, run, all, get) => {
|
|||||||
|
|
||||||
await run(
|
await run(
|
||||||
'INSERT INTO users (id, identifier, password_hash, role, created_at, auth_provider, oidc_issuer, oidc_sub) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
'INSERT INTO users (id, identifier, password_hash, role, created_at, auth_provider, oidc_issuer, oidc_sub) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||||
[crypto.randomUUID(), identifier, hashPassword(plainPassword), 'admin', new Date().toISOString(), 'local', null, null],
|
[randomUUID(), identifier, hashPassword(plainPassword), 'admin', new Date().toISOString(), 'local', null, null],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!email || !password) {
|
if (!email || !password) {
|
||||||
@@ -181,37 +178,104 @@ const initDb = async (db, run, all, get) => {
|
|||||||
export async function getDb() {
|
export async function getDb() {
|
||||||
if (dbInstance) return dbInstance
|
if (dbInstance) return dbInstance
|
||||||
|
|
||||||
const db = new sqlite3.Database(getDbPath(), (err) => {
|
const sqliteDb = (() => {
|
||||||
if (err) {
|
try {
|
||||||
|
return new DatabaseSync(getDbPath(), { timeout: DB_BUSY_TIMEOUT_MS })
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
console.error('[db] Failed to open database:', err.message)
|
console.error('[db] Failed to open database:', err.message)
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
})
|
})()
|
||||||
|
|
||||||
const run = promisify(db.run.bind(db))
|
const run = (sql, params = []) =>
|
||||||
const all = promisify(db.all.bind(db))
|
new Promise((resolve, reject) => {
|
||||||
const get = promisify(db.get.bind(db))
|
const stmt = sqliteDb.prepare(sql)
|
||||||
|
try {
|
||||||
|
stmt.run(...params)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
stmt.finalize()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// ignore finalize errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const all = (sql, params = []) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const stmt = sqliteDb.prepare(sql)
|
||||||
|
try {
|
||||||
|
const rows = stmt.all(...params)
|
||||||
|
resolve(rows)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
stmt.finalize()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// ignore finalize errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const get = (sql, params = []) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const stmt = sqliteDb.prepare(sql)
|
||||||
|
try {
|
||||||
|
const row = stmt.get(...params)
|
||||||
|
resolve(row)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
stmt.finalize()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// ignore finalize errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrappedDb = {
|
||||||
|
close(callback) {
|
||||||
|
try {
|
||||||
|
sqliteDb.close()
|
||||||
|
if (typeof callback === 'function') callback(null)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if (typeof callback === 'function') callback(error)
|
||||||
|
else throw error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await initDb(db, run, all, get)
|
await initDb(wrappedDb, run, all, get)
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
db.close()
|
wrappedDb.close()
|
||||||
console.error('[db] Database initialization failed:', error.message)
|
console.error('[db] Database initialization failed:', error.message)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
dbInstance = { db, run, all, get }
|
dbInstance = { db: wrappedDb, run, all, get }
|
||||||
|
|
||||||
registerCleanup(async () => {
|
registerCleanup(async () => {
|
||||||
if (dbInstance) {
|
if (dbInstance) {
|
||||||
try {
|
try {
|
||||||
await new Promise((resolve, reject) => {
|
dbInstance.db.close()
|
||||||
dbInstance.db.close((err) => {
|
|
||||||
if (err) reject(err)
|
|
||||||
else resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('[db] Error closing database during shutdown:', error?.message)
|
console.error('[db] Error closing database during shutdown:', error?.message)
|
||||||
@@ -290,9 +354,7 @@ export async function withTransaction(db, callback) {
|
|||||||
export function closeDb() {
|
export function closeDb() {
|
||||||
if (!dbInstance) return
|
if (!dbInstance) return
|
||||||
try {
|
try {
|
||||||
dbInstance.db.close((err) => {
|
dbInstance.db.close()
|
||||||
if (err) console.error('[db] Error closing database:', err.message)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('[db] Error closing database:', error.message)
|
console.error('[db] Error closing database:', error.message)
|
||||||
|
|||||||
Reference in New Issue
Block a user