1. Project Overview & Quickstart (nelvko/LICENSE)
Technical Documentation: nelvko/LICENSE
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
LICENSE
Agent Skills & Rules
- Discovered 21 agent rule(s) and prompt configurations.
--- METRICS ---
- Files Extracted: 1
- Estimated Token Budget: ~24 tokens
- Canonical Reference: https://codewiki.google/github.com/nelvko/LICENSE
2. Official Technical Reference & Guides (nelvko/docs)
File: docs/contribution/issue.md
title: 问题反馈
:::info
如果您在使用过程中遇到了什么问题,您可以通过下面的方式反馈,但请尽量按照要求提出反馈。
:::
GitHub Issues
链接:https://github.com/halo-dev/halo/issues
如果你在使用过程中,遇到了一些 bug 或者需要添加某些新特性,请尽量在 GitHub Issues 进行反馈,这非常有助于我们跟踪解决此问题,您也可以很方便的接收到处理状态。
建议步骤:
- 在 Issues 列表 搜索相关问题,看看是否有其他人已经提到了此问题。
- 如果当前还没有人遇到您类似的问题,那么请点击右上角的
New issue按钮创建新的 issue。 - 选择正确的反馈类型。
- 请尽可能详细的按照模板填写内容。
- 点击
Submit new issue提交 issue。
Halo 官方社区
此平台主要目的用于与其他 Halo 用户进行交流。但如果您对 GitHub 不是很熟悉或者没有账号,您也可以在此平台进行反馈。
File: docs/contribution/pr.md
title: 代码贡献
欢迎关注并有想法参与 Halo 的开发,以下是关于如何参与到 Halo 项目的指南,仅供参考。
发现 Issue
所有的代码尽可能都有依据(Issue),不是凭空产生。
寻找一个 Good First Issue
这个步骤非常适合首次贡献者。
在 halo-dev 和 halo-sigs 组织下,有非常多的仓库。每个仓库下都有可能包含一些“首次贡献者”友好的 Issue,主要是为了给贡献者提供一个友好的体验。 该类 Issue
一般会用 good-first-issue 标签标记。标签 good-first-issue 表示该 Issue 不需要对 Halo 有深入的理解也能够参与。
请点击:good-first-issue
查看关于 Halo 的 Good First Issue。
认领 Issue
若对任何一个 Issue 感兴趣,请尝试在 Issue 进行回复,讨论解决 Issue 的思路。确定后可直接通过 /assign 或者 /assign @GitHub 用户名 认领这个
Issue。这样可避免两位贡献者在同一个问题上花时间。
代码贡献步骤
Fork 此仓库
点击 Halo 仓库主页右上角的
Fork按钮即可。Clone 仓库到本地
bashgit clone https://github.com/{YOUR_USERNAME}/halo --recursive # 或者 git clone [email protected]:{YOUR_USERNAME}/halo.git --recursive添加主仓库
添加主仓库方便未来同步主仓库最新的 commits 以及创建新的分支。
bashgit remote add upstream https://github.com/halo-dev/halo.git # 或者 git remote add upstream [email protected]:halo-dev/halo.git git fetch upstream main创建新的开发分支
我们需要从主仓库的主分支创建一个新的开发分支。
bashgit checkout upstream/main git checkout -b {BRANCH_NAME}提交代码
bashgit add . git commit -s -m "Fix a bug king" git push origin {BRANCH_NAME}合并主分支
在提交 Pull Request 之前,尽量保证当前分支和主分支的代码尽可能同步,这时需要我们手动操作。示例:
bashgit fetch upstream/main git merge upstream/main git push origin {BRANCH_NAME}
Pull Request
进入此阶段说明已经完成了代码的编写,测试和自测,并且准备好接受 Code Review。
创建 Pull Request
回到自己的仓库页面,选择 New pull request 按钮,创建 Pull request 到原仓库的 main 分支。
然后等待我们 Review 即可,如有 Change Request,再本地修改之后再次提交即可。
提交 Pull Request 的注意事项:
- 提交 Pull Request 请充分自测。
- 每个 Pull Request 尽量只解决一个 Issue,特殊情况除外。
- 应尽可能多的添加单元测试,其他测试(集成测试和 E2E 测试)可看情况添加。
- 不论需要解决的 Issue 发生在哪个版本,提交 Pull Request 的时候,请将主仓库的主分支设置为
main。例如:即使某个 Bug 于 Halo 2.0.x 被发现,但是提交 Pull Request 仍只针对main分支,等待 Pull Request 合并之后,我们会通过/cherrypick release-2.0或者/cherry-pick release-2.1指令将此 Pull Request
的修改应用到release-2.0和release-2.1分支上。
更新 commits
Code Review 阶段可能需要 Pull Request 作者重新修改代码,请直接在当前分支 commit 并 push 即可,无需关闭并重新提交 Pull Request。示例:
git add .
git commit -s -m "Refactor some code according code review"
git push origin bug/king同时,若已经进入 Code Review 阶段,请不要强制推送 commits 到当前分支。否则 Reviewers 需要从头开始 Code Review。
开发规范
请参考 https://docs.halo.run/developer-guide/core/code-style
,请确保所有代码格式化之后再提交。
File: docs/contribution/sponsor.md
title: 赞助我们
为什么需要赞助
我们花费了大量的精力来维护这个软件,并且也提供了不少资金来维护服务器,域名等。因此我们需要赞助来节省部分开发成本。你的赞助不仅仅会被我们用来支付一些开发成本(比如服务器,OSS,域名等),还会让我们有更多的信心和精力投入到这个开源项目的开发中。从而让项目保持更加健康的成长以及迭代。
赞助形式
:::info
你可以通过任何形式对我们赞助,不限于资金。
:::
资金赞助
通过我们的推广链接购买服务器
如果你当前还没有购买服务器,可以考虑通过以下链接购买,这会为我们带来一部分收益。
- 阿里云:https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=j57gyupo
- 阿里云新人专享:https://www.aliyun.com/minisite/goods?userCode=j57gyupo
- 腾讯云:https://curl.qcloud.com/9Ogon25Y
File: docs/developer-guide/core/build.md
title: 构建
:::info
在此之前,我们推荐你先阅读《准备工作》,检查本地环境是否满足要求。
:::
一般情况下,为了保证版本一致性和可维护性,我们并不推荐自行构建和二次开发。
克隆项目
如果你已经 Fork 了相关仓库,请将以下命令中的 halo-dev 替换为你的 GitHub 用户名。
git clone https://github.com/halo-dev/halo
# 或者使用 ssh 的方式 clone(推荐)
# git clone [email protected]:halo-dev/halo.git
# 或者使用 GitHub CLI 克隆(推荐)
# gh repo clone halo-dev/halo
# 或者使用 GitHub CLI Fork(推荐)
# gh repo fork halo-dev/halo
cd halo
# 切换到特定的分支或标签,请替换 ${branch_name}
git checkout ${branch_name}构建 Fat Jar
构建之前需要修改 gradle.properties 中的 version 属性(推荐遵循 SemVer 规范),例如:version=2.13.0
cd path/to/halo下载预设插件(可选):
# Windows
./gradlew.bat downloadPluginPresets
# macOS / Linux
./gradlew downloadPluginPresets构建:
# Windows
./gradlew.bat clean build -x check
# macOS / Linux
./gradlew clean build -x check构建完成之后,在 Halo 项目下产生的 application/build/libs/halo-${version}.jar 即为构建完成的文件。
最终部署文档可参考:使用 JAR 文件部署。
构建 Docker 镜像
在此之前,请确认已经构建好了 Fat Jar。
cd path/to/halo# 请替换 ${tag_name}
docker build -t halo-dev/halo:${tag_name} .# 插件构建完成的版本
docker images | grep halo最终部署文档可参考:使用 Docker Compose 部署。
File: docs/developer-guide/core/code-style.md
title: 代码风格
Halo 添加了 checkstyle 插件,来保证每位提交者代码的风格保持一致,减少无效代码的修改。本篇文章主要讲解如何在 IDEA 中添加 CheckStyle 插件,并引入项目所提供的 checkstyle.xml 配置。
安装 CheckStyle-IDEA
- 进入 IDEA 插件市场。
- 搜索 CheckStyle-IDEA,点击安装即可。
配置 CheckStyle
- 进入 CheckStyle 配置(File | Settings | Tools | Checkstyle)。
- 选择 Checkstyle 版本:9.3(以文件
application/build.gradle中指定的版本为准)。 - 在配置文件中点击添加按钮,配置描述可随便填写(推荐 Halo Checks),选择 ./config/checkstyle/checkstyle.xml,点击下一步和完成。
- 勾选刚刚创建的配置文件。
配置 Editor
进入编辑器配置(File | Settings | Editor | Code Style)
导入 checkstyle.xm 配置:
选择
./config/checkstyle/checkstyle.xml配置文件,点击确定即可。
至此,有关代码风格检查工具和格式化配置已经完成。
File: docs/developer-guide/core/prepare.md
title: 准备工作
环境要求
名词解释
工作目录
指 Halo 所依赖的工作目录,在 Halo 运行的时候会在系统当前用户目录下产生一个 halo-next 的文件夹,绝对路径为 ~/halo-next。里面通常包含下列目录或文件:
db:存放 H2 Database 的物理文件,如果你使用其他数据库,那么不会存在这个目录。themes:里面包含用户所安装的主题。plugins:里面包含用户所安装的插件。attachments:附件目录。logs:运行日志目录。
File: docs/developer-guide/core/run.md
title: 开发环境运行
:::info
在此之前,我们推荐你先阅读《准备工作》,检查本地环境是否满足要求。
:::
项目结构说明
目前如果需要完整的运行 Halo,总共需要三个部分:
- Halo 主项目(halo-dev/halo)
- UI,包括 Console 控制台和 UC 个人中心(托管在 Halo 主项目)
- 主题(Halo 主项目内已包含默认主题)
:::info 说明
从 Halo 2.13 开始,Halo 项目的 ui 目录同时包含了 Console(管理控制台)和 UC(个人中心),以下统称为 UI。
当前 Halo 主项目并不会将 UI 的构建资源托管到 Git 版本控制,所以在开发环境是需要同时运行 UI 项目的。当然,在我们的最终发布版本的时候会在 CI 中自动构建 UI 到 Halo 主项目。
:::
克隆项目
如果你已经 Fork 了相关仓库,请将以下命令中的 halo-dev 替换为你的 GitHub 用户名。
git clone https://github.com/halo-dev/halo
# 或者使用 ssh 的方式 clone(推荐)
# git clone [email protected]:halo-dev/halo.git
# 或者使用 GitHub CLI 克隆(推荐)
# gh repo clone halo-dev/halo
# 或者使用 GitHub CLI Fork(推荐)
# gh repo fork halo-dev/halo运行 UI 服务
cd path/to/haloLinux / macOS 平台:
./gradlew :ui:devWindows 平台:
./gradlew.bat :ui:dev最终控制台打印了如下信息即代表运行正常:
VITE v4.2.3 ready in 638 ms
# Console 控制台服务
➜ Local: http://localhost:3000/console/
# UC 个人中心服务
➜ Local: http://localhost:4000/uc/:::info 提示
请不要直接使用 UI 的运行端口(3000 / 4000)访问,会因为跨域问题导致无法正常登录,建议按照后续的步骤以 dev 的配置文件运行 Halo,在 dev 的配置文件中,我们默认代理了 UI 页面的访问地址,所以后续访问 UI 页面使用 http://localhost:8090/console 和 http://localhost:8090/uc 访问即可,代理的相关配置:
halo:
console:
proxy:
endpoint: http://localhost:3000/
enabled: true
uc:
proxy:
endpoint: http://localhost:4000/
enabled: true:::
运行 Halo
在 IntelliJ IDEA 中打开 Halo 项目,等待 Gradle 初始化和依赖下载完成。
下载预设插件(可选)
bash# Windows ./gradlew.bat downloadPluginPresets # macOS / Linux ./gradlew downloadPluginPresets修改 IntelliJ IDEA 的运行配置
Windows
将 Active Profiles 改为
dev,win,如图所示:macOS / Linux
将 Active Profiles 改为
dev,如图所示:
点击 IntelliJ IDEA 的运行按钮,等待项目启动完成。
或者使用 Gradle 运行
bash# macOS / Linux ./gradlew bootRun --args="--spring.profiles.active=dev" # Windows gradlew.bat bootRun --args="--spring.profiles.active=dev,win"最终提供以下访问地址:
- 网站首页:http://localhost:8090
- Console 控制台:http://localhost:8090/console
- UC 个人中心:http://localhost:8090/uc
File: docs/developer-guide/core/structure.md
title: 系统结构
Halo 博客系统分为以下四个部分:
| 项目名称 | 简介 |
|---|---|
| halo | 提供整个系统的服务,采用 Spring Boot 开发 |
| halo-admin | 负责后台管理的渲染,采用 Vue 开发,已集成在 Halo 运行包内,无需独立部署。 |
| halo-comment | 评论插件,采用 Vue 开发,在主题中运行方式引入构建好的 JavaScript 文件即可 |
| halo-theme-* | 主题项目集,采用 FreeMarker 模板引擎编写,需要包含一些特殊的配置才能够被 halo 所使用 |
自定义配置
为什么要提前讲自定义配置呢?是因为在这里让大家了解到
Halo的配置方式,以及配置优先级,不至于未来运行项目的时候不知道如何优雅地修改配置。
Halo 配置目录优先级如下(从上到下优先级越来越小,上层的配置将会覆盖下层):
Halo自定义配置- file:~/.halo/
- file:~/.halo-dev/
Spring Boot默认配置- file:./config/
- file:./
- classpath:/config/
- classpath:/
在开发的时候,希望大家能够在 ~/halo-dev/application.yml 中进行添加自定义配置。当然后面也会讲到如何用运行参数 和 VM options 进行控制配置,届时可根据具体情况进行选择。
:::warning
开发的时候,我们不建议直接更改项目源码中的所包含的配置文件,包括 application.yml、application-dev.yml、application-test.yml 和 application-user.yml。
:::
File: docs/developer-guide/plugin/api-reference/ui/extension-points/interface/Attachment.md
export interface Attachment {
apiVersion: "storage.halo.run/v1alpha1"
kind: "Attachment"
metadata: {
annotations: {}
creationTimestamp: string
labels: {}
name: string // 附件的唯一标识
version: number
}
spec: {
displayName: string // 附件名称
groupName: string // 附件分组
mediaType: string // 附件类型
ownerName: string // 附件上传者
policyName: string // 附件存储策略
size: number // 附件大小
tags: Array<string>
}
status: {
permalink: string // 附件固定访问地址
}
}File: docs/developer-guide/plugin/api-reference/ui/extension-points/interface/ListedPost.md
export interface ListedPost {
categories: Array<{ // 文章的分类集合
apiVersion: "content.halo.run/v1alpha1";
kind: "Category";
metadata: {
annotations: {};
creationTimestamp: string;
labels: {};
name: string; // 分类的唯一标识
version: number;
};
spec: {
children: Array<string>; // 子分类
cover: string; // 分类封面图
description: string; // 分类描述
displayName: string; // 分类名称
priority: number; // 分类优先级
slug: string; // 分类别名
template: string; // 分类渲染模板
};
status: {
permalink: string; // 分类的永久链接
postCount: number; // 分类下的文章总数
visiblePostCount: number; // 分类下可见的文章总数
};
}>;
contributors: Array<{ // 文章的贡献者集合
avatar: string; // 贡献者头像
displayName: string; // 贡献者名称
name: string; // 贡献者唯一标识
}>;
owner: { // 文章的作者信息
avatar: string; // 作者头像
displayName: string; // 作者名称
name: string; // 作者唯一标识
};
post: { // 文章信息
apiVersion: "content.halo.run/v1alpha1";
kind: "Post";
metadata: {
annotations: {};
creationTimestamp: string;
labels: {};
name: string; // 文章的唯一标识
version: number;
};
spec: {
allowComment: boolean; // 是否允许评论
baseSnapshot: string; // 内容基础快照
categories: Array<string>; // 文章所属分类
cover: string; // 文章封面图
deleted: boolean; // 是否已删除
excerpt: { // 文章摘要
autoGenerate: boolean; // 是否自动生成
raw: string; // 摘要内容
};
headSnapshot: string; // 内容最新快照
htmlMetas: Array<{}>;
owner: string; // 文章作者的唯一标识
pinned: boolean; // 是否置顶
priority: number; // 文章优先级
publish: boolean; // 是否发布
publishTime: string; // 发布时间
releaseSnapshot: string; // 已发布的内容快照
slug: string; // 文章别名
tags: Array<string>; // 文章所属标签
template: string; // 文章渲染模板
title: string; // 文章标题
visible: string; // 文章可见性
};
status: {
commentsCount: number; // 文章评论总数
conditions: Array<{
lastTransitionTime: string;
message: string;
reason: string;
status: string;
type: string;
}>;
contributors: Array<string>;
excerpt: string; // 最终的文章摘要,根据是否自动生成计算
inProgress: boolean; // 是否有未发布的内容
lastModifyTime: string; // 文章最后修改时间
permalink: string; // 文章的永久链接
phase: string;
};
};
stats: {
approvedComment: number; // 已审核的评论数
totalComment: number; // 评论总数
upvote: number; // 点赞数
visit: number; // 访问数
};
tags: Array<{ // 文章的标签集合
apiVersion: "content.halo.run/v1alpha1";
kind: "Tag";
metadata: {
annotations: {};
creationTimestamp: string;
labels: {};
name: string; // 标签的唯一标识
version: number;
};
spec: {
color: string; // 标签颜色
cover: string; // 标签封面图
displayName: string; // 标签名称
slug: string; // 标签别名
};
status: {
permalink: string; // 标签的永久链接
postCount: number; // 标签下的文章总数
visiblePostCount: number; // 标签下可见的文章总数
};
}>;
}File: docs/developer-guide/plugin/api-reference/ui/extension-points/interface/OperationItem.md
export interface OperationItem<T> {
priority: number; // 排序优先级
component: Raw<Component>; // 菜单项组件
props?: Record<string, unknown>; // 菜单项组件属性
action?: (item?: T) => void; // 菜单项点击事件
label?: string; // 菜单项标题
hidden?: boolean; // 菜单项是否隐藏
permissions?: string[]; // 菜单项 UI 权限
children?: OperationItem<T>[]; // 子菜单项
}File: docs/developer-guide/plugin/api-reference/ui/extension-points/interface/Plugin.md
export interface Plugin {
apiVersion: "plugin.halo.run/v1alpha1"
kind: "Plugin"
metadata: {
annotations: {}
creationTimestamp: string // 创建时间
labels: {}
name: string // 唯一标识
version: number
}
spec: {
author: { // 作者信息
name: string
website: string
}
configMapName: string // 关联的 ConfigMap 模型,用于存储配置
description: string // 插件描述
displayName: string // 插件名称
enabled: boolean
homepage: string // 插件主页
license: Array<{ // 插件协议
name: string
url: string
}>
logo: string
pluginDependencies: {}
repo: string // 插件仓库地址
requires: string // 所依赖的 Halo 版本
settingName: string // 关联的 Setting 模型,用于渲染配置表单
version: string // 插件版本
}
status: {
conditions: Array<{
lastTransitionTime: string
message: string
reason: string
status: string
type: string
}>
entry: string
lastProbeState: string
lastStartTime: string
loadLocation: string
logo: string // 插件 Logo 地址
phase: string
stylesheet: string
}
}