mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 22:02:09 +08:00
ci: 添加 GitLab CI/CD 配置并实现自动化流程- 新增 .gitlab-ci.main.yml、.gitlab-ci.other.yml 和 .gitlab-ci.test.yml 文件
- 实现了 build、tag、publish、reset 和 mirror等阶段的自动化流程 - 添加了 check 和 test 分支的构建和发布配置 - 更新了 build.gradle.kts 和 settings.gradle.kts 文件,调整了项目配置 - 新增 MdcContextElement 和 CoroutineMdcWebFilter 类,用于协程中的 MDC 上下文传播
This commit is contained in:
parent
5f3e078e0f
commit
3bfcf98e21
2
.gitignore
vendored
2
.gitignore
vendored
@ -21,7 +21,7 @@ build/
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
/temp
|
||||
### Kotlin ###
|
||||
.kotlin
|
||||
|
||||
|
||||
10
.gitlab-ci.yml
Normal file
10
.gitlab-ci.yml
Normal file
@ -0,0 +1,10 @@
|
||||
include:
|
||||
- local: '/.gitlab/workflows/.gitlab-ci.test.yml'
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "test"'
|
||||
- local: '/.gitlab/workflows/.gitlab-ci.main.yml'
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
- local: '/.gitlab/workflows/.gitlab-ci.other.yml'
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH != "test"'
|
||||
131
.gitlab/workflows/.gitlab-ci.main.yml
Normal file
131
.gitlab/workflows/.gitlab-ci.main.yml
Normal file
@ -0,0 +1,131 @@
|
||||
stages:
|
||||
- build
|
||||
- tag
|
||||
- publish
|
||||
- reset
|
||||
- mirror
|
||||
|
||||
variables:
|
||||
GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"
|
||||
|
||||
before_script:
|
||||
- rm -rf $GRADLE_USER_HOME/.tmp || true
|
||||
|
||||
# ✅ Build 阶段
|
||||
build:
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- gradle/libs.versions.toml
|
||||
- "**/*.gradle.kts"
|
||||
prefix: lab-agent
|
||||
paths:
|
||||
- .gradle/caches/
|
||||
- .gradle/wrapper/
|
||||
- .gradle/kotlin-profile/
|
||||
- .kotlin/
|
||||
policy: pull-push
|
||||
script:
|
||||
- ./gradlew clean build
|
||||
tags:
|
||||
- java
|
||||
|
||||
# 🏷️ 自动打标签
|
||||
tag:
|
||||
stage: tag
|
||||
needs: [ "build" ]
|
||||
image: alpine:latest
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- set -euo pipefail
|
||||
- apk add --no-cache git
|
||||
- git config --global user.email "pipeline@${GITLAB_URL}"
|
||||
- git config --global user.name "Project Pipeline Bot"
|
||||
- git fetch --tags
|
||||
- git fetch origin main
|
||||
- MAIN_COMMIT=$(git rev-parse origin/main)
|
||||
- echo "🔗 main commit -> $MAIN_COMMIT"
|
||||
|
||||
- LATEST_TAG=$(git tag --list '*' --sort=-v:refname | head -n1 || true)
|
||||
- if [ -z "$LATEST_TAG" ]; then LATEST_TAG="0.0.0"; fi
|
||||
- echo "🔖 最新 tag -> $LATEST_TAG"
|
||||
|
||||
- VERSION=${LATEST_TAG#v}
|
||||
- MAJOR=$(echo "$VERSION" | cut -d. -f1)
|
||||
- MINOR=$(echo "$VERSION" | cut -d. -f2)
|
||||
- PATCH=$(echo "$VERSION" | cut -d. -f3)
|
||||
|
||||
- PATCH=$((PATCH + 1))
|
||||
- NEW_TAG="${MAJOR}.${MINOR}.${PATCH}"
|
||||
- echo "🏷️ 新 tag -> $NEW_TAG"
|
||||
|
||||
- if git tag --points-at "$MAIN_COMMIT" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' > /dev/null; then
|
||||
echo "⏭️ 已存在 tag,跳过创建";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
- git tag $NEW_TAG $MAIN_COMMIT
|
||||
- git push https://oauth2:${PIPELINE_BOT_TOKEN}@${GITLAB_URL}/${CI_PROJECT_PATH}.git $NEW_TAG
|
||||
- echo "✅ tag $NEW_TAG 已推送"
|
||||
tags:
|
||||
- java
|
||||
|
||||
# 📦 发布至 GitLab Maven 仓库
|
||||
publish:
|
||||
stage: publish
|
||||
needs: [ "tag" ]
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- ./gradlew publishMavenJavaPublicationToGitLabRepository
|
||||
tags:
|
||||
- java
|
||||
|
||||
# 🔄 重建 test 分支
|
||||
reset:
|
||||
stage: reset
|
||||
needs: [ "build" ]
|
||||
image: alpine:latest
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- set -euo pipefail
|
||||
- apk add --no-cache git
|
||||
- git config --global user.email "pipeline@${GITLAB_URL}"
|
||||
- git config --global user.name "Project Pipeline Bot"
|
||||
- git clone --depth=1 --branch main https://oauth2:${PIPELINE_BOT_TOKEN}@${GITLAB_URL}/${CI_PROJECT_PATH}.git repo
|
||||
- cd repo
|
||||
- git checkout -B test
|
||||
- git push origin test --force
|
||||
- echo "✅ test 分支已重建完成"
|
||||
tags:
|
||||
- java
|
||||
# Mirror to GitHub
|
||||
mirror-to-github:
|
||||
stage: mirror
|
||||
needs: [ "build" ]
|
||||
image: alpine:latest
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- set -euo pipefail
|
||||
- apk add --no-cache git openssh
|
||||
- git config --global user.name "Project Pipeline Bot"
|
||||
- git config --global user.email "pipeline@${GITLAB_URL}"
|
||||
|
||||
- echo "🔄 正在 clone 当前 GitLab 仓库..."
|
||||
- git clone --depth=1 --branch main https://oauth2:${PIPELINE_BOT_TOKEN}@${GITLAB_URL}/${CI_PROJECT_PATH}.git repo
|
||||
- cd repo
|
||||
|
||||
- echo "🔗 添加 GitHub 远程地址..."
|
||||
- git remote add github https://x-access-token:${GITHUB_PUSH_TOKEN}@github.com/GeWuYou/forgeboot.git
|
||||
|
||||
- echo "🚀 推送 main 分支到 GitHub..."
|
||||
- git push github main --force
|
||||
- echo "✅ GitHub 同步完成"
|
||||
tags:
|
||||
- java
|
||||
44
.gitlab/workflows/.gitlab-ci.other.yml
Normal file
44
.gitlab/workflows/.gitlab-ci.other.yml
Normal file
@ -0,0 +1,44 @@
|
||||
stages:
|
||||
- check
|
||||
before_script:
|
||||
- export GRADLE_USER_HOME=$CI_PROJECT_DIR/.gradle
|
||||
- rm -rf $CI_PROJECT_DIR/.gradle/.tmp || true
|
||||
# ✅ check Job
|
||||
check:
|
||||
stage: check
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- gradle/libs.versions.toml
|
||||
- "**/build.gradle.kts"
|
||||
prefix: lab-agent
|
||||
paths:
|
||||
- .gradle/caches/
|
||||
- .gradle/wrapper/
|
||||
- .gradle/kotlin-profile/
|
||||
- .kotlin/
|
||||
- buildSrc/.gradle/
|
||||
- buildSrc/build/
|
||||
policy: pull-push
|
||||
script:
|
||||
- echo "🔧 授予 gradlew 执行权限..."
|
||||
- chmod +x gradlew
|
||||
|
||||
- echo "🧪 开始快速编译检查(跳过打包和测试)..."
|
||||
- ./gradlew compileKotlin compileJava --stacktrace || (echo "❌ 编译失败!请检查错误日志" && exit 1)
|
||||
|
||||
- echo "📦 当前缓存目录:"
|
||||
- ls -la .gradle/
|
||||
|
||||
- echo "📦 Gradle 缓存结构检查"
|
||||
- ls -la .gradle/caches/modules-2/files-2.1 || true
|
||||
- echo "📦 缓存文件数量:$(find .gradle/caches/modules-2/files-2.1 -type f | wc -l)"
|
||||
|
||||
- echo "🛑 停止 Gradle 守护进程..."
|
||||
- ./gradlew --stop
|
||||
|
||||
- echo "🔍 当前 Java 进程:"
|
||||
- ps aux | grep java || true
|
||||
tags:
|
||||
- docker
|
||||
- java
|
||||
24
.gitlab/workflows/.gitlab-ci.test.yml
Normal file
24
.gitlab/workflows/.gitlab-ci.test.yml
Normal file
@ -0,0 +1,24 @@
|
||||
stages:
|
||||
- build
|
||||
- publish
|
||||
|
||||
# 🧪 test 构建
|
||||
build:
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "test"'
|
||||
script:
|
||||
- ./gradlew clean build
|
||||
tags:
|
||||
- java
|
||||
|
||||
# 🧪 test 发布 SNAPSHOT 包(允许覆盖)
|
||||
publish:
|
||||
stage: publish
|
||||
needs: ["build"]
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == "test"'
|
||||
script:
|
||||
- ./gradlew publishMavenJavaPublicationToGitLabRepository
|
||||
tags:
|
||||
- java
|
||||
@ -11,13 +11,10 @@ plugins {
|
||||
// Kotlin kapt 支持
|
||||
alias(libs.plugins.kotlin.kapt)
|
||||
id(libs.plugins.kotlin.jvm.get().pluginId)
|
||||
alias(libs.plugins.gradleMavenPublishPlugin)
|
||||
}
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
// alias(libs.plugins.gradleMavenPublishPlugin)
|
||||
}
|
||||
|
||||
|
||||
// 配置 SCM 版本插件
|
||||
scmVersion {
|
||||
tag {
|
||||
@ -93,27 +90,26 @@ subprojects {
|
||||
tasks.named<Jar>("sourcesJar") {
|
||||
dependsOn("generateI18nKeys")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
apply {
|
||||
plugin(libs.plugins.java.get().pluginId)
|
||||
plugin(libs.plugins.javaLibrary.get().pluginId)
|
||||
// plugin(libs.plugins.java.get().pluginId)
|
||||
// plugin(libs.plugins.javaLibrary.get().pluginId)
|
||||
plugin(libs.plugins.maven.publish.get().pluginId)
|
||||
plugin(libs.plugins.kotlin.jvm.get().pluginId)
|
||||
plugin(libs.plugins.axionRelease.get().pluginId)
|
||||
plugin(libs.plugins.kotlin.kapt.get().pluginId)
|
||||
plugin(libs.plugins.gradleMavenPublishPlugin.get().pluginId)
|
||||
// plugin(libs.plugins.gradleMavenPublishPlugin.get().pluginId)
|
||||
// 导入仓库配置
|
||||
from(file("$configDir/repositories.gradle.kts"))
|
||||
}
|
||||
// 中央仓库
|
||||
mavenPublishing {
|
||||
publishToMavenCentral("DEFAULT", true)
|
||||
signAllPublications()
|
||||
}
|
||||
// // 中央仓库
|
||||
// mavenPublishing {
|
||||
// publishToMavenCentral("https://s01.oss.sonatype.org/", true)
|
||||
// signAllPublications()
|
||||
// }
|
||||
// 发布配置
|
||||
publishing {
|
||||
repositories {
|
||||
@ -131,6 +127,17 @@ subprojects {
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "GitLab"
|
||||
url = uri("https://gitlab.snow-lang.com/api/v4/projects/18/packages/maven")
|
||||
credentials(HttpHeaderCredentials::class) {
|
||||
name = "Private-Token"
|
||||
value = System.getenv("PIPELINE_BOT_TOKEN") // 存储为 GitLab CI/CD Secret
|
||||
}
|
||||
authentication {
|
||||
create("header", HttpHeaderAuthentication::class)
|
||||
}
|
||||
}
|
||||
// Gitea 仓库
|
||||
val host = System.getenv("GITEA_HOST")
|
||||
host?.let {
|
||||
|
||||
@ -6,4 +6,5 @@ dependencies {
|
||||
implementation(platform(libs.springBootDependencies.bom))
|
||||
implementation(libs.springBoot.autoconfigure)
|
||||
implementation(libs.jackson.databind)
|
||||
implementation(libs.kotlinxCoroutines.reactor)
|
||||
}
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package com.gewuyou.forgeboot.context.impl.element
|
||||
|
||||
import kotlinx.coroutines.ThreadContextElement
|
||||
import org.slf4j.MDC
|
||||
import kotlin.coroutines.AbstractCoroutineContextElement
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* MDC上下文元素,用于在协程中传播MDC(Mapped Diagnostic Context)上下文。
|
||||
*
|
||||
* MDC 是 SLF4J 提供的一个日志诊断工具,允许将特定信息绑定到当前线程的上下文中,
|
||||
* 以便在日志输出时能够包含这些信息。由于协程可能在线程间切换,因此需要此实现来保证上下文一致性。
|
||||
*
|
||||
* @param contextMap 包含 MDC 上下文键值对的不可变 Map,用于保存和恢复诊断上下文。
|
||||
* @since 2025-07-16 11:05:47
|
||||
* @author gewuyou
|
||||
*/
|
||||
class MdcContextElement(
|
||||
private val contextMap: Map<String, String>
|
||||
) : ThreadContextElement<Map<String, String>>,
|
||||
AbstractCoroutineContextElement(Key) {
|
||||
|
||||
/**
|
||||
* 协程上下文键对象,用于标识此类上下文元素的唯一性。
|
||||
*/
|
||||
companion object Key : CoroutineContext.Key<MdcContextElement>
|
||||
|
||||
/**
|
||||
* 更新当前线程的 MDC 上下文为协程指定的上下文,并返回旧的上下文状态。
|
||||
*
|
||||
* 此方法会在协程切换至新线程时调用,以确保目标线程的 MDC 上下文与协程一致。
|
||||
*
|
||||
* @param context 当前协程的上下文,不直接使用但保留用于扩展。
|
||||
* @return 返回更新前的 MDC 上下文状态,用于后续恢复。
|
||||
*/
|
||||
override fun updateThreadContext(context: CoroutineContext): Map<String, String> {
|
||||
val oldState = MDC.getCopyOfContextMap() ?: emptyMap()
|
||||
MDC.setContextMap(contextMap)
|
||||
return oldState
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复当前线程的 MDC 上下文至先前保存的状态。
|
||||
*
|
||||
* 此方法在协程完成执行并释放线程资源时调用,确保线程可以还原其原始 MDC 上下文。
|
||||
*
|
||||
* @param context 当前协程的上下文,不直接使用但保留用于扩展。
|
||||
* @param oldState 需要恢复的先前 MDC 上下文状态。
|
||||
*/
|
||||
override fun restoreThreadContext(context: CoroutineContext, oldState: Map<String, String>) {
|
||||
MDC.setContextMap(oldState)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.gewuyou.forgeboot.context.impl.filter
|
||||
|
||||
import com.gewuyou.forgeboot.context.impl.element.MdcContextElement
|
||||
import kotlinx.coroutines.reactive.awaitFirstOrNull
|
||||
import kotlinx.coroutines.reactor.mono
|
||||
import org.springframework.web.server.ServerWebExchange
|
||||
import org.springframework.web.server.WebFilter
|
||||
import org.springframework.web.server.WebFilterChain
|
||||
import reactor.core.publisher.Mono
|
||||
import java.util.stream.Collectors
|
||||
|
||||
/**
|
||||
* 协程 MDC Web 过滤器
|
||||
*
|
||||
* 用于在响应式编程环境下,将上下文(如 MDC)从 Reactor Context 传递到 Kotlin 协程中,
|
||||
* 确保日志上下文信息能够正确传播。
|
||||
*
|
||||
* @since 2025-07-16 11:07:44
|
||||
* @author gewuyou
|
||||
*/
|
||||
class CoroutineMdcWebFilter : WebFilter {
|
||||
|
||||
/**
|
||||
* 执行过滤操作的方法
|
||||
*
|
||||
* @param exchange 表示当前的服务器 Web 交换信息,包含请求和响应
|
||||
* @param chain 当前的过滤器链,用于继续执行后续的过滤器或目标处理器
|
||||
* @return 返回一个 Mono<Void>,表示异步完成的过滤操作
|
||||
*/
|
||||
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
|
||||
return Mono.deferContextual { ctxView ->
|
||||
// 从 Reactor 上下文中提取键值对,筛选出 key 和 value 均为 String 类型的条目
|
||||
val mdcMap = ctxView.stream()
|
||||
.filter { it.key is String && it.value is String }
|
||||
.collect(Collectors.toMap(
|
||||
{ it.key as String },
|
||||
{ it.value as String }
|
||||
))
|
||||
|
||||
// 在带有 MDC 上下文的协程中执行过滤链
|
||||
mono(MdcContextElement(mdcMap)) {
|
||||
chain.filter(exchange).awaitFirstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.springBootStarter.jpa)
|
||||
implementation(project(Modules.Webmvc.DTO))
|
||||
implementation(project(Modules.Core.EXTENSION))
|
||||
api(project(Modules.Webmvc.DTO))
|
||||
api(project(Modules.Core.EXTENSION))
|
||||
}
|
||||
|
||||
@ -136,42 +136,42 @@ project(":forgeboot-trace:forgeboot-trace-impl").name = "forgeboot-trace-impl"
|
||||
project(":forgeboot-trace:forgeboot-trace-autoconfigure").name = "forgeboot-trace-autoconfigure"
|
||||
//endregion
|
||||
|
||||
//region module security
|
||||
/**
|
||||
* Includes and configures projects related to 'forgeboot-security'
|
||||
* This module handles security-related functionality.
|
||||
*/
|
||||
include(
|
||||
"forgeboot-security",
|
||||
":forgeboot-security:forgeboot-security-core",
|
||||
|
||||
":forgeboot-security:forgeboot-security-authenticate",
|
||||
":forgeboot-security:forgeboot-security-authenticate:api",
|
||||
":forgeboot-security:forgeboot-security-authenticate:impl",
|
||||
":forgeboot-security:forgeboot-security-authenticate:autoconfigure",
|
||||
|
||||
":forgeboot-security:forgeboot-security-authorize",
|
||||
":forgeboot-security:forgeboot-security-authorize:api",
|
||||
":forgeboot-security:forgeboot-security-authorize:impl",
|
||||
":forgeboot-security:forgeboot-security-authorize:autoconfigure"
|
||||
)
|
||||
project(":forgeboot-security").name = "forgeboot-security-spring-boot-starter"
|
||||
project(":forgeboot-security:forgeboot-security-core").name = "forgeboot-security-core"
|
||||
|
||||
project(":forgeboot-security:forgeboot-security-authenticate").name =
|
||||
"forgeboot-security-authenticate-spring-boot-starter"
|
||||
project(":forgeboot-security:forgeboot-security-authenticate:api").name = "forgeboot-security-authenticate-api"
|
||||
project(":forgeboot-security:forgeboot-security-authenticate:impl").name = "forgeboot-security-authenticate-impl"
|
||||
project(":forgeboot-security:forgeboot-security-authenticate:autoconfigure").name =
|
||||
"forgeboot-security-authenticate-autoconfigure"
|
||||
|
||||
project(":forgeboot-security:forgeboot-security-authorize").name = "forgeboot-security-authorize-spring-boot-starter"
|
||||
project(":forgeboot-security:forgeboot-security-authorize:api").name = "forgeboot-security-authorize-api"
|
||||
project(":forgeboot-security:forgeboot-security-authorize:impl").name = "forgeboot-security-authorize-impl"
|
||||
project(":forgeboot-security:forgeboot-security-authorize:autoconfigure").name =
|
||||
"forgeboot-security-authorize-autoconfigure"
|
||||
|
||||
//endregion
|
||||
////region module security
|
||||
///**
|
||||
// * Includes and configures projects related to 'forgeboot-security'
|
||||
// * This module handles security-related functionality.
|
||||
// */
|
||||
//include(
|
||||
// "forgeboot-security",
|
||||
// ":forgeboot-security:forgeboot-security-core",
|
||||
//
|
||||
// ":forgeboot-security:forgeboot-security-authenticate",
|
||||
// ":forgeboot-security:forgeboot-security-authenticate:api",
|
||||
// ":forgeboot-security:forgeboot-security-authenticate:impl",
|
||||
// ":forgeboot-security:forgeboot-security-authenticate:autoconfigure",
|
||||
//
|
||||
// ":forgeboot-security:forgeboot-security-authorize",
|
||||
// ":forgeboot-security:forgeboot-security-authorize:api",
|
||||
// ":forgeboot-security:forgeboot-security-authorize:impl",
|
||||
// ":forgeboot-security:forgeboot-security-authorize:autoconfigure"
|
||||
//)
|
||||
//project(":forgeboot-security").name = "forgeboot-security-spring-boot-starter"
|
||||
//project(":forgeboot-security:forgeboot-security-core").name = "forgeboot-security-core"
|
||||
//
|
||||
//project(":forgeboot-security:forgeboot-security-authenticate").name =
|
||||
// "forgeboot-security-authenticate-spring-boot-starter"
|
||||
//project(":forgeboot-security:forgeboot-security-authenticate:api").name = "forgeboot-security-authenticate-api"
|
||||
//project(":forgeboot-security:forgeboot-security-authenticate:impl").name = "forgeboot-security-authenticate-impl"
|
||||
//project(":forgeboot-security:forgeboot-security-authenticate:autoconfigure").name =
|
||||
// "forgeboot-security-authenticate-autoconfigure"
|
||||
//
|
||||
//project(":forgeboot-security:forgeboot-security-authorize").name = "forgeboot-security-authorize-spring-boot-starter"
|
||||
//project(":forgeboot-security:forgeboot-security-authorize:api").name = "forgeboot-security-authorize-api"
|
||||
//project(":forgeboot-security:forgeboot-security-authorize:impl").name = "forgeboot-security-authorize-impl"
|
||||
//project(":forgeboot-security:forgeboot-security-authorize:autoconfigure").name =
|
||||
// "forgeboot-security-authorize-autoconfigure"
|
||||
//
|
||||
////endregion
|
||||
|
||||
//region module cache
|
||||
include(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user