first commit
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
This commit is contained in:
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: usememos
|
||||
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
name: Bug Report
|
||||
description: If something isn't working as expected
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to report a bug! Please complete the form below to help us understand and fix the issue.
|
||||
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: Pre-submission Checklist
|
||||
description: Please confirm you have completed the following steps before submitting
|
||||
options:
|
||||
- label: I have searched the existing issues and this bug has not been reported yet
|
||||
required: true
|
||||
- label: I have tested this issue on the [demo site](https://demo.usememos.com) or the latest version
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: issue-location
|
||||
attributes:
|
||||
label: Where did you encounter this bug?
|
||||
description: Select where you tested and confirmed this issue
|
||||
options:
|
||||
- Latest stable version (self-hosted)
|
||||
- Latest development version (self-hosted)
|
||||
- Demo site (demo.usememos.com)
|
||||
- Older version (please specify below)
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Memos Version
|
||||
description: Provide the exact version (e.g., `v0.25.2`). Find this in Settings → About or via `--version` flag
|
||||
placeholder: v0.25.2
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: A clear and concise description of what the bug is
|
||||
placeholder: When I try to..., the application...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Detailed steps to reproduce the behavior
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: What did you expect to happen?
|
||||
placeholder: I expected...
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Screenshots & Additional Context
|
||||
description: Add screenshots, browser/OS info, deployment method (Docker/binary), or any other relevant details
|
||||
placeholder: |
|
||||
- Browser: Chrome 120
|
||||
- OS: macOS 14
|
||||
- Deployment: Docker
|
||||
- Database: SQLite
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
76
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
76
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: Feature Request
|
||||
description: If you have a suggestion for a new feature
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for suggesting a new feature! Please complete the form below to help us understand your idea.
|
||||
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: Pre-submission Checklist
|
||||
description: Please confirm you have completed the following steps before submitting
|
||||
options:
|
||||
- label: I have searched the existing issues and this feature has not been requested yet
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: feature-type
|
||||
attributes:
|
||||
label: Type of Feature
|
||||
description: What type of feature is this?
|
||||
options:
|
||||
- User Interface (UI)
|
||||
- User Experience (UX)
|
||||
- API / Backend
|
||||
- Documentation
|
||||
- Integrations / Plugins
|
||||
- Security / Privacy
|
||||
- Performance
|
||||
- Other
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: problem-statement
|
||||
attributes:
|
||||
label: Problem or Use Case
|
||||
description: What problem does this feature solve? What are you trying to accomplish?
|
||||
placeholder: |
|
||||
I often need to... but currently there's no way to...
|
||||
This would help me/users to...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposed-solution
|
||||
attributes:
|
||||
label: Proposed Solution
|
||||
description: A clear and concise description of what you want to happen
|
||||
placeholder: |
|
||||
It would be great if Memos could...
|
||||
For example, a button/feature that...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: Have you considered any alternative solutions or workarounds?
|
||||
placeholder: |
|
||||
I've tried... but it doesn't work well because...
|
||||
An alternative could be...
|
||||
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context, mockups, screenshots, or examples about the feature request
|
||||
placeholder: |
|
||||
- Similar feature in other apps: ...
|
||||
- Mockups or screenshots: ...
|
||||
- Related discussions: ...
|
||||
91
.github/workflows/backend-tests.yml
vendored
Normal file
91
.github/workflows/backend-tests.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Backend Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- "**.go"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25.7"
|
||||
|
||||
jobs:
|
||||
static-checks:
|
||||
name: Static Checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
cache-dependency-path: go.sum
|
||||
|
||||
- name: Verify go.mod is tidy
|
||||
run: |
|
||||
go mod tidy -go=${{ env.GO_VERSION }}
|
||||
git diff --exit-code
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v2.4.0
|
||||
args: --timeout=3m
|
||||
|
||||
tests:
|
||||
name: Tests (${{ matrix.test-group }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test-group: [store, server, plugin, other]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
cache-dependency-path: go.sum
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
case "${{ matrix.test-group }}" in
|
||||
store)
|
||||
# Run store tests for all drivers (sqlite, mysql, postgres)
|
||||
go test -v -coverprofile=coverage.out -covermode=atomic ./store/...
|
||||
;;
|
||||
server)
|
||||
go test -v -race -coverprofile=coverage.out -covermode=atomic ./server/...
|
||||
;;
|
||||
plugin)
|
||||
go test -v -race -coverprofile=coverage.out -covermode=atomic ./plugin/...
|
||||
;;
|
||||
other)
|
||||
go test -v -race -coverprofile=coverage.out -covermode=atomic \
|
||||
./cmd/... ./internal/... ./proto/...
|
||||
;;
|
||||
esac
|
||||
env:
|
||||
DRIVER: ${{ matrix.test-group == 'store' && '' || 'sqlite' }}
|
||||
|
||||
- name: Upload coverage
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./coverage.out
|
||||
flags: ${{ matrix.test-group }}
|
||||
fail_ci_if_error: false
|
||||
231
.github/workflows/build-binaries.yml
vendored
Normal file
231
.github/workflows/build-binaries.yml
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
name: Build Binaries
|
||||
|
||||
# Build multi-platform binaries on release or manual trigger
|
||||
# Produces distributable packages for Linux, macOS, and Windows
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
# Environment variables for build configuration
|
||||
env:
|
||||
GO_VERSION: "1.25.7"
|
||||
NODE_VERSION: "22"
|
||||
PNPM_VERSION: "10"
|
||||
ARTIFACT_RETENTION_DAYS: 60
|
||||
# Artifact naming: {ARTIFACT_PREFIX}_{version}_{os}_{arch}.tar.gz|zip
|
||||
ARTIFACT_PREFIX: memos
|
||||
|
||||
jobs:
|
||||
# Job 1: Extract version information
|
||||
# - For git tags: use tag version (e.g., v0.28.1 -> 0.28.1)
|
||||
# - For branches: use branch-name-shortSHA format
|
||||
prepare:
|
||||
name: Extract Version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # Full history for git describe
|
||||
|
||||
- name: Extract version
|
||||
id: version
|
||||
run: |
|
||||
# Try to get version from git tag
|
||||
TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")
|
||||
if [ -n "$TAG" ]; then
|
||||
echo "version=${TAG#v}" >> $GITHUB_OUTPUT
|
||||
echo "Version from tag: ${TAG#v}"
|
||||
else
|
||||
# Use branch name + short SHA
|
||||
BRANCH="${GITHUB_REF_NAME//\//-}"
|
||||
SHORT_SHA="${GITHUB_SHA:0:7}"
|
||||
echo "version=${BRANCH}-${SHORT_SHA}" >> $GITHUB_OUTPUT
|
||||
echo "Version from branch: ${BRANCH}-${SHORT_SHA}"
|
||||
fi
|
||||
|
||||
# Job 2: Build frontend assets
|
||||
# - Builds React frontend with Vite
|
||||
# - Produces static files that will be embedded in Go binary
|
||||
# - Shared across all platform builds
|
||||
build-frontend:
|
||||
name: Build Frontend
|
||||
needs: prepare
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: pnpm
|
||||
cache-dependency-path: web/pnpm-lock.yaml
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('web/pnpm-lock.yaml') }}
|
||||
restore-keys: ${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: web
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: web
|
||||
run: pnpm release
|
||||
|
||||
- name: Upload frontend artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
|
||||
|
||||
# Job 3: Build Go binaries for multiple platforms
|
||||
# - Cross-compiles using native Go toolchain
|
||||
# - Embeds frontend assets built in previous job
|
||||
# - Produces static binaries with no external dependencies
|
||||
# - Packages as tar.gz (Unix) or zip (Windows)
|
||||
build-binaries:
|
||||
name: Build ${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm && format('v{0}', matrix.goarm) || '' }}
|
||||
needs: [prepare, build-frontend]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Linux targets
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
# macOS targets
|
||||
- goos: darwin
|
||||
goarch: amd64 # Intel Macs
|
||||
- goos: darwin
|
||||
goarch: arm64 # Apple Silicon
|
||||
# Windows targets
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Download frontend artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
|
||||
- name: Build binary
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
CGO_ENABLED: "0"
|
||||
run: |
|
||||
# Determine output binary name
|
||||
OUTPUT_NAME="memos"
|
||||
if [ "$GOOS" = "windows" ]; then
|
||||
OUTPUT_NAME="memos.exe"
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
|
||||
# Build static binary with optimizations
|
||||
go build \
|
||||
-trimpath \
|
||||
-ldflags="-s -w -extldflags '-static'" \
|
||||
-tags netgo,osusergo \
|
||||
-o "build/${OUTPUT_NAME}" \
|
||||
./cmd/memos
|
||||
|
||||
echo "✓ Built: build/${OUTPUT_NAME}"
|
||||
ls -lh build/
|
||||
|
||||
- name: Package binary
|
||||
id: package
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
run: |
|
||||
cd build
|
||||
|
||||
# Construct package name: {prefix}_{version}_{os}_{arch}[v{arm_version}]
|
||||
PACKAGE_NAME="${ARTIFACT_PREFIX}_${VERSION}_${GOOS}_${GOARCH}"
|
||||
if [ -n "$GOARM" ]; then
|
||||
PACKAGE_NAME="${PACKAGE_NAME}v${GOARM}"
|
||||
fi
|
||||
|
||||
# Package based on platform
|
||||
if [ "$GOOS" = "windows" ]; then
|
||||
ARTIFACT_NAME="${PACKAGE_NAME}.zip"
|
||||
zip -q "${ARTIFACT_NAME}" memos.exe
|
||||
else
|
||||
ARTIFACT_NAME="${PACKAGE_NAME}.tar.gz"
|
||||
tar czf "${ARTIFACT_NAME}" memos
|
||||
fi
|
||||
|
||||
# Output for next step
|
||||
echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
|
||||
echo "✓ Package created: ${ARTIFACT_NAME} ($(du -h "${ARTIFACT_NAME}" | cut -f1))"
|
||||
|
||||
- name: Upload binary artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_NAME }}
|
||||
path: build/${{ env.ARTIFACT_NAME }}
|
||||
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
|
||||
|
||||
# Job 4: Upload artifacts to GitHub Release
|
||||
# - Only runs when triggered by a release publish event
|
||||
# - Downloads all built artifacts and attaches them to the release
|
||||
release:
|
||||
name: Upload Release Assets
|
||||
needs: build-binaries
|
||||
if: github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: ${{ env.ARTIFACT_PREFIX }}_*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*
|
||||
|
||||
166
.github/workflows/build-canary-image.yml
vendored
Normal file
166
.github/workflows/build-canary-image.yml
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
name: Build Canary Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.repository }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4.2.0
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "22"
|
||||
cache: pnpm
|
||||
cache-dependency-path: "web/pnpm-lock.yaml"
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('web/pnpm-lock.yaml') }}
|
||||
restore-keys: ${{ runner.os }}-pnpm-store-
|
||||
- run: pnpm install --frozen-lockfile
|
||||
working-directory: web
|
||||
- name: Run frontend build
|
||||
run: pnpm release
|
||||
working-directory: web
|
||||
|
||||
- name: Upload frontend artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
retention-days: 1
|
||||
|
||||
build-push:
|
||||
needs: build-frontend
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Download frontend artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./scripts/Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
cache-from: type=gha,scope=build-${{ matrix.platform }}
|
||||
cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }}
|
||||
outputs: type=image,name=neosmemo/memos,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: digests-${{ strategy.job-index }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
needs: build-push
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
path: /tmp/digests
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
neosmemo/memos
|
||||
ghcr.io/usememos/memos
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=raw,value=canary
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf 'neosmemo/memos@sha256:%s ' *)
|
||||
env:
|
||||
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }}
|
||||
|
||||
- name: Inspect images
|
||||
run: |
|
||||
docker buildx imagetools inspect neosmemo/memos:canary
|
||||
docker buildx imagetools inspect ghcr.io/usememos/memos:canary
|
||||
184
.github/workflows/build-stable-image.yml
vendored
Normal file
184
.github/workflows/build-stable-image.yml
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
name: Build Stable Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "release/**"
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Extract version
|
||||
id: version
|
||||
run: |
|
||||
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
|
||||
echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version=${GITHUB_REF_NAME#release/}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
build-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4.2.0
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "22"
|
||||
cache: pnpm
|
||||
cache-dependency-path: "web/pnpm-lock.yaml"
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('web/pnpm-lock.yaml') }}
|
||||
restore-keys: ${{ runner.os }}-pnpm-store-
|
||||
- run: pnpm install --frozen-lockfile
|
||||
working-directory: web
|
||||
- name: Run frontend build
|
||||
run: pnpm release
|
||||
working-directory: web
|
||||
|
||||
- name: Upload frontend artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
retention-days: 1
|
||||
|
||||
build-push:
|
||||
needs: [prepare, build-frontend]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm/v7
|
||||
- linux/arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Download frontend artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: server/router/frontend/dist
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./scripts/Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
cache-from: type=gha,scope=build-${{ matrix.platform }}
|
||||
cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }}
|
||||
outputs: type=image,name=neosmemo/memos,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: digests-${{ strategy.job-index }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
needs: [prepare, build-push]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
path: /tmp/digests
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
neosmemo/memos
|
||||
ghcr.io/usememos/memos
|
||||
tags: |
|
||||
type=semver,pattern={{version}},value=${{ needs.prepare.outputs.version }}
|
||||
type=semver,pattern={{major}}.{{minor}},value=${{ needs.prepare.outputs.version }}
|
||||
type=raw,value=stable
|
||||
flavor: |
|
||||
latest=false
|
||||
labels: |
|
||||
org.opencontainers.image.version=${{ needs.prepare.outputs.version }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf 'neosmemo/memos@sha256:%s ' *)
|
||||
env:
|
||||
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }}
|
||||
|
||||
- name: Inspect images
|
||||
run: |
|
||||
docker buildx imagetools inspect neosmemo/memos:stable
|
||||
docker buildx imagetools inspect ghcr.io/usememos/memos:stable
|
||||
17
.github/workflows/demo-deploy.yml
vendored
Normal file
17
.github/workflows/demo-deploy.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: Demo Deploy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-demo:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger Render Deploy
|
||||
run: |
|
||||
curl -X POST "${{ secrets.RENDER_DEPLOY_HOOK }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"trigger": "github_action"}'
|
||||
|
||||
- name: Deployment Status
|
||||
run: echo "Demo deployment triggered successfully on Render"
|
||||
72
.github/workflows/frontend-tests.yml
vendored
Normal file
72
.github/workflows/frontend-tests.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
name: Frontend Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "web/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
NODE_VERSION: "22"
|
||||
PNPM_VERSION: "10"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: pnpm
|
||||
cache-dependency-path: web/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: web
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run lint
|
||||
working-directory: web
|
||||
run: pnpm lint
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: pnpm
|
||||
cache-dependency-path: web/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: web
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: web
|
||||
run: pnpm build
|
||||
40
.github/workflows/proto-linter.yml
vendored
Normal file
40
.github/workflows/proto-linter.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Proto Linter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "proto/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint Protos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup buf
|
||||
uses: bufbuild/buf-setup-action@v1
|
||||
with:
|
||||
github_token: ${{ github.token }}
|
||||
|
||||
- name: Run buf lint
|
||||
uses: bufbuild/buf-lint-action@v1
|
||||
with:
|
||||
input: proto
|
||||
|
||||
- name: Check buf format
|
||||
run: |
|
||||
if [[ $(buf format -d) ]]; then
|
||||
echo "❌ Proto files are not formatted. Run 'buf format -w' to fix."
|
||||
exit 1
|
||||
fi
|
||||
24
.github/workflows/stale.yml
vendored
Normal file
24
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Close Stale
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 */8 * * *" # Every 8 hours
|
||||
|
||||
jobs:
|
||||
close-stale:
|
||||
name: Close Stale Issues and PRs
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Mark and close stale issues and PRs
|
||||
uses: actions/stale@v10.1.1
|
||||
with:
|
||||
# Issues: mark stale after 14 days of inactivity, close after 3 more days
|
||||
days-before-issue-stale: 14
|
||||
days-before-issue-close: 3
|
||||
|
||||
# Pull requests: mark stale after 14 days of inactivity, close after 3 more days
|
||||
days-before-pr-stale: 14
|
||||
days-before-pr-close: 3
|
||||
Reference in New Issue
Block a user