From ee727490b1126249c1799faf91f5487e014b1100 Mon Sep 17 00:00:00 2001 From: mianbin Date: Sat, 22 Mar 2025 11:07:19 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=AE=E5=89=8D=E7=9A=84=E6=B5=81=E6=B0=B4?= =?UTF-8?q?=E7=BA=BF=E6=A8=A1=E5=9E=8B=EF=BC=8C=E4=B8=8D=E5=AE=8C=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/$PROJECT_FILE$ | 11 + .idea/.gitignore | 8 + .idea/CopilotChatHistory.xml | 657 ++++++++++++ .idea/MarsCodeWorkspaceAppSettings.xml | 7 + .idea/compiler.xml | 92 ++ .idea/encodings.xml | 79 ++ .idea/inspectionProfiles/Project_Default.xml | 5 + .idea/jarRepositories.xml | 30 + .idea/misc.xml | 40 + .idea/qaplug_profiles.xml | 933 ++++++++++++++++++ .idea/uiDesigner.xml | 124 +++ .idea/vcs.xml | 6 + dependencies/.flattened-pom.xml | 41 + dependencies/pom.xml | 29 +- framework/commons/pom.xml | 16 + .../commons/exception/ErrorCode.java | 9 +- .../enums/GlobalErrorCodeConstants.java | 4 +- .../commons/util/cache/CacheUtils.java | 2 +- .../commons/util/encrypt/AESUtil.java | 89 ++ .../commons/util/encrypt/DHKeyPair.java | 41 + .../commons/util/encrypt/DHUtil.java | 106 ++ .../commons/util/generator/IdGenerator.java | 34 + .../commons/util/http/OkhttpUtils.java | 72 ++ .../commons/util/reflect/ReflectUtil.java | 22 + .../commons/util/retry/RetryUtils.java | 33 + .../commons/util/string/StrUtils.java | 1 - .../commons/util/validation/ValidGroup.java | 21 + .../commons/util/watcher/LogUtils.java | 44 + .../commons/util/watcher/Watcher.java | 82 ++ .../config/OpsTracerAutoConfiguration.java | 2 +- .../mybatis/core/dataobject/BaseDO.java | 2 +- .../config/OpsRedisAutoConfiguration.java | 6 + .../redis/core/RedisTemplateUtils.java | 570 +++++++++++ .../handler/AuthenticationEntryPointImpl.java | 2 +- .../apilog/core/enums/OperateTypeEnum.java | 2 +- .../system/enums/ErrorCodeConstants.java | 19 +- .../system/dal/dataobject/dept/DeptDO.java | 2 - .../system/dal/dataobject/dept/PostDO.java | 2 +- .../dal/dataobject/dept/UserPostDO.java | 2 - .../dal/dataobject/dict/DictDataDO.java | 2 +- .../dal/dataobject/dict/DictTypeDO.java | 2 +- .../dal/dataobject/mail/MailAccountDO.java | 3 +- .../dal/dataobject/notice/NoticeDO.java | 2 +- .../dal/dataobject/permission/MenuDO.java | 2 +- .../dal/dataobject/permission/RoleDO.java | 2 +- .../dal/dataobject/permission/RoleMenuDO.java | 2 +- .../dal/dataobject/permission/UserRoleDO.java | 2 +- .../dal/dataobject/tenant/TenantDO.java | 2 +- .../system/service/dict/DictDataService.java | 2 +- .../service/dict/DictDataServiceImpl.java | 2 +- modules/pipeline-ci-commons/pom.xml | 31 + .../commons/constant/BaseConstant.java | 19 + .../commons/constant/CommonConstants.java | 136 +++ .../commons/constant/CommonMessageCode.java | 222 +++++ .../commons/constant/LeafAllocConstant.java | 64 ++ .../pipeline/commons/constant/OpsHeader.java | 70 ++ .../pipeline/commons/enums/BkStyleEnum.java | 38 + .../commons/enums/CommonStatusEnum.java | 38 + .../commons/enums/DateIntervalEnum.java | 46 + .../commons/enums/SubjectScopeType.java | 27 + .../commons/enums/SystemModuleEnum.java | 62 ++ .../pipeline/commons/enums/UserTypeEnum.java | 41 + .../commons/functions/Preconditions.java | 23 + .../commons/operationid/LeafAllocMapper.java | 15 + .../commons/operationid/LeafAllocService.java | 29 + .../operationid/LeafAllocServiceImpl.java | 82 ++ .../operationid/SegmentIdGeneratorImpl.java | 304 ++++++ .../commons/operationid/entity/LeafAlloc.java | 60 ++ .../commons/operationid/entity/Segment.java | 28 + .../operationid/entity/SegmentBuffer.java | 73 ++ .../commons/operationid/entity/Status.java | 11 + modules/pipeline-ci-event/pom.xml | 22 + .../src/main/java/cd/casic/pipeline/Main.java | 13 + modules/pipeline-ci-log/pom.xml | 39 + .../cd/casic/pipeline/api/AppLogResource.java | 278 ++++++ .../pipeline/api/BuildLogPrintResource.java | 127 +++ .../cd/casic/pipeline/api/OpLogResource.java | 18 + .../pipeline/api/ServiceLogPrintResource.java | 86 ++ .../pipeline/api/ServiceLogResource.java | 173 ++++ .../casic/pipeline/api/UserLogResource.java | 195 ++++ .../pipeline/api/impl/AppLogResourceImpl.java | 61 ++ .../api/impl/BuildLogPrintResourceImpl.java | 126 +++ .../pipeline/api/impl/OpLogResourceImpl.java | 16 + .../api/impl/ServiceLogPrintResourceImpl.java | 83 ++ .../api/impl/ServiceLogResourceImpl.java | 51 + .../api/impl/UserLogResourceImpl.java | 82 ++ .../pipeline/config/BuildLogPrinter.java | 22 + .../casic/pipeline/dal/dao/IndexMapper.java | 50 + .../pipeline/dal/dao/LogStatusMapper.java | 15 + .../casic/pipeline/dal/dao/LogTahMapper.java | 45 + .../pipeline/dal/dataobject/LogIndicesV2.java | 55 ++ .../pipeline/dal/dataobject/LogStatus.java | 49 + .../pipeline/dal/dataobject/LogSubTags.java | 44 + .../pipeline/dal/pojo/EndPageQueryLogs.java | 29 + .../cd/casic/pipeline/dal/pojo/LogLine.java | 41 + .../pipeline/dal/pojo/PageQueryLogs.java | 27 + .../pipeline/dal/pojo/QueryLogLineNum.java | 24 + .../pipeline/dal/pojo/QueryLogStatus.java | 23 + .../cd/casic/pipeline/dal/pojo/QueryLogs.java | 35 + .../dal/pojo/TaskBuildLogProperty.java | 27 + .../pipeline/dal/pojo/message/LogMessage.java | 34 + .../pojo/message/LogMessageWithLineNo.java | 25 + .../cd/casic/pipeline/dal/pojo/meta/Ansi.java | 133 +++ .../pipeline/dal/pojo/meta/AnsiAttribute.java | 28 + .../pipeline/dal/pojo/meta/AnsiColor.java | 35 + .../pipeline/enums/LogErrorCodeEnum.java | 20 + .../casic/pipeline/enums/LogStatusEnum.java | 52 + .../casic/pipeline/enums/LogStorageMode.java | 29 + .../java/cd/casic/pipeline/enums/LogType.java | 21 + .../cd/casic/pipeline/event/log/IEvent.java | 12 + .../casic/pipeline/event/log/ILogEvent.java | 26 + .../pipeline/event/log/LogOriginEvent.java | 30 + .../pipeline/event/log/LogStatusEvent.java | 24 + .../pipeline/event/log/LogStorageEvent.java | 26 + .../casic/pipeline/jmx/CreateIndexBean.java | 55 ++ .../cd/casic/pipeline/jmx/LogStorageBean.java | 55 ++ .../service/BuildLogListenerService.java | 99 ++ .../service/BuildLogPrintService.java | 56 ++ .../service/BuildLogQueryService.java | 178 ++++ .../casic/pipeline/service/IndexService.java | 180 ++++ .../cd/casic/pipeline/service/LogService.java | 109 ++ .../pipeline/service/LogServiceImpl.java | 237 +++++ .../pipeline/service/LogStatusService.java | 90 ++ .../casic/pipeline/service/LogTagService.java | 102 ++ modules/pipeline-ci-market/pom.xml | 24 + .../market/constant/StoreMessageCode.java | 135 +++ modules/pipeline-ci-process/pom.xml | 75 ++ .../pipeline/process/dal/package-info.java | 7 + .../casic/pipeline/process/utils/AESUtil.java | 86 ++ .../pipeline/process/utils/CommonUtils.java | 16 + .../pipeline/process/utils/LogUtils.java | 42 + .../pipeline/process/utils/RetryUtils.java | 30 + modules/pipeline-ci-project/pom.xml | 38 + .../project/constant/ProjectConstants.java | 17 + .../UserProjectResourceController.java | 39 + .../project/dal/dao/ProjectMapper.java | 21 + .../pipeline/project/dal/dto/Project.java | 236 +++++ .../dal/pojo/AuthProjectCreateInfo.java | 30 + .../dal/pojo/PipelineAsCodeSettings.java | 15 + .../dal/pojo/ProjectCreateExtInfo.java | 15 + .../project/dal/pojo/ProjectCreateInfo.java | 45 + .../project/dal/pojo/ProjectProperties.java | 12 + .../pipeline/project/dal/pojo/ProjectVO.java | 133 +++ .../dal/pojo/ResourceRegisterInfo.java | 13 + .../project/dal/pojo/SubjectScopeInfo.java | 25 + .../project/dal/pojo/user/UserDeptDetail.java | 29 + .../project/enums/ProjectApproveStatus.java | 45 + .../enums/ProjectAuthSecrecyStatus.java | 32 + .../project/enums/ProjectChannelCode.java | 18 + .../project/enums/ProjectValidateType.java | 6 + .../project/service/ProjectExtService.java | 9 + .../service/ProjectPermissionService.java | 8 + .../service/UserProjectResourceService.java | 9 + .../BluekingProjectPermissionServiceImpl.java | 18 + .../service/impl/ProjectExtServiceImpl.java | 16 + .../service/impl/ProjectServiceImpl.java | 209 ++++ .../impl/UserProjectResourceServiceImpl.java | 30 + modules/pipeline-ci-quality/pom.xml | 24 + .../api/ServiceQualityRuleResource.java | 31 + .../pipeline/constants/QualityConstants.java | 67 ++ .../cd/casic/pipeline/dal/package-info.java | 7 + .../pipeline/dal/pojo/RuleCheckResult.java | 23 + .../dal/pojo/RuleCheckSingleResult.java | 14 + .../pipeline/dal/v2/ControlPointPosition.java | 37 + .../casic/pipeline/dal/v3/package-info.java | 7 + .../dal/v3/request/BuildCheckParamsV3.java | 39 + modules/pipeline-ci-scm-repository/pom.xml | 38 + .../src/main/java/cd/casic/pipeline/Main.java | 13 + .../scm/api/ServiceGithubResource.java | 59 ++ .../scm/api/ServiceGithubResourceImpl.java | 43 + .../scm/api/ServiceOauthResource.java | 31 + .../scm/api/ServiceOauthResourceImpl.java | 29 + .../scm/api/ServiceRepositoryResource.java | 32 + .../api/ServiceRepositoryResourceImpl.java | 40 + .../scm/api/scm/ServiceScmOauthResource.java | 92 ++ .../api/scm/ServiceScmOauthResourceImpl.java | 36 + .../scm/api/scm/ServiceScmResource.java | 92 ++ .../scm/api/scm/ServiceScmResourceImpl.java | 33 + .../casic/pipeline/scm/config/GitConfig.java | 73 ++ .../casic/pipeline/scm/config/P4Config.java | 19 + .../casic/pipeline/scm/config/SVNConfig.java | 25 + .../scm/dal/dao/RepositoryGitTokenMapper.java | 14 + .../dal/dao/RepositoryGitlabTokenMapper.java | 15 + .../scm/dal/dao/RepositoryRecordMapper.java | 14 + .../dal/dao/RepositoryTGitTokenMapper.java | 13 + .../scm/dal/dto/RepositoryGitToken.java | 52 + .../scm/dal/dto/RepositoryGitlabToken.java | 33 + .../scm/dal/dto/RepositoryRecord.java | 44 + .../scm/dal/dto/RepositoryTGitToken.java | 40 + .../scm/dal/pojo/CodeGitRepository.java | 38 + .../scm/dal/pojo/CodeGitlabRepository.java | 39 + .../scm/dal/pojo/CodeP4Repository.java | 17 + .../scm/dal/pojo/CodeSvnRepository.java | 48 + .../scm/dal/pojo/CodeTGitRepository.java | 41 + .../pipeline/scm/dal/pojo/Credential.java | 17 + .../scm/dal/pojo/GithubRepository.java | 18 + .../cd/casic/pipeline/scm/dal/pojo/IScm.java | 10 + .../pipeline/scm/dal/pojo/Repository.java | 43 + .../pipeline/scm/dal/pojo/RevisionInfo.java | 23 + .../pipeline/scm/dal/pojo/ScmFactory.java | 77 ++ .../scm/dal/pojo/ScmOauthFactory.java | 62 ++ .../pipeline/scm/dal/pojo/git/GitApi.java | 10 + .../scm/dal/pojo/git/GitOauthApi.java | 9 + .../scm/dal/pojo/git/GitUserInfo.java | 29 + .../scm/dal/pojo/github/GithubBranch.java | 14 + .../scm/dal/pojo/github/GithubCommit.java | 17 + .../dal/pojo/github/GithubCommitAuthor.java | 18 + .../scm/dal/pojo/github/GithubCommitData.java | 15 + .../scm/dal/pojo/github/GithubObject.java | 19 + .../scm/dal/pojo/github/GithubTag.java | 22 + .../scm/dal/pojo/github/GithubToken.java | 21 + .../pipeline/scm/dal/pojo/oauth/GitToken.java | 34 + .../scm/dal/pojo/svn/CodeGitScmImpl.java | 44 + .../scm/dal/pojo/svn/CodeGitlabScmImpl.java | 41 + .../scm/dal/pojo/svn/CodeP4ScmImpl.java | 36 + .../scm/dal/pojo/svn/CodeSvnScmImpl.java | 38 + .../scm/dal/pojo/svn/CodeTGitScmImpl.java | 44 + .../scm/enums/CodeGitWebhookEvent.java | 37 + .../pipeline/scm/enums/CodeSvnRegion.java | 36 + .../pipeline/scm/enums/GitHubTokenType.java | 15 + .../pipeline/scm/enums/RepoAuthType.java | 22 + .../pipeline/scm/enums/RepositoryConfig.java | 54 + .../pipeline/scm/enums/RepositoryType.java | 16 + .../pipeline/scm/enums/RepositoryTypeNew.java | 18 + .../scm/enums/RequestChannelTypeEnum.java | 10 + .../cd/casic/pipeline/scm/enums/ScmType.java | 30 + .../pipeline/scm/enums/TokenTypeEnum.java | 13 + .../CodeRepositoryServiceRegistrar.java | 60 ++ .../scm/service/IGitOauthService.java | 11 + .../service/code/CodeRepositoryService.java | 10 + .../scm/service/github/GithubService.java | 157 +++ .../service/github/GithubTokenService.java | 10 + .../github/GithubTokenServiceImpl.java | 32 + .../scm/service/github/IGithubService.java | 12 + .../scm/service/impl/GitOauthServiceImpl.java | 100 ++ .../service/impl/RepositoryServiceImpl.java | 64 ++ .../scm/service/scm/GitServiceImpl.java | 51 + .../pipeline/scm/service/scm/IGitService.java | 9 + .../scm/service/scm/IScmOauthService.java | 15 + .../pipeline/scm/service/scm/IScmService.java | 15 + .../scm/service/scm/ScmOauthServiceImpl.java | 59 ++ .../scm/service/scm/ScmServiceImpl.java | 73 ++ .../scm/service/tgit/ITGitService.java | 13 + .../scm/service/tgit/TGitOauthService.java | 9 + .../service/tgit/TGitOauthServiceImpl.java | 18 + .../scm/service/tgit/TGitServiceImpl.java | 87 ++ .../scm/service/tgit/TGitTokenService.java | 11 + .../service/tgit/TGitTokenServiceImpl.java | 99 ++ .../cd/casic/pipeline/scm/utils/GitUtils.java | 18 + .../cd/casic/pipeline/scm/utils/HashUtil.java | 48 + .../scm/utils/RepositoryConfigUtils.java | 16 + .../pipeline/scm/utils/WebhookUtils.java | 20 + modules/pipeline-ci-ticket/pom.xml | 33 + .../api/ServiceCredentialResource.java | 32 + .../impl/ServiceCredentialResourceImpl.java | 30 + .../pipeline/constant/TicketMessageCode.java | 23 + .../dal/dao/CredentialRecordMapper.java | 13 + .../dal/dataobject/CredentialRecord.java | 47 + .../pipeline/dal/enums/CredentialType.java | 68 ++ .../java/cd/casic/pipeline/dal/pojo/Cert.java | 35 + .../casic/pipeline/dal/pojo/Credential.java | 38 + .../pipeline/dal/pojo/CredentialInfo.java | 35 + .../pipeline/service/CredentialHelper.java | 37 + .../pipeline/service/CredentialService.java | 12 + .../service/CredentialServiceImpl.java | 74 ++ .../src/main/resources/application-dev.yaml | 4 +- .../src/main/resources/application-local.yaml | 4 +- pom.xml | 9 + 268 files changed, 13370 insertions(+), 49 deletions(-) create mode 100644 .idea/$PROJECT_FILE$ create mode 100644 .idea/.gitignore create mode 100644 .idea/CopilotChatHistory.xml create mode 100644 .idea/MarsCodeWorkspaceAppSettings.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/qaplug_profiles.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java create mode 100644 framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java create mode 100644 framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java create mode 100644 modules/pipeline-ci-commons/pom.xml create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/BaseConstant.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonConstants.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonMessageCode.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/LeafAllocConstant.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/OpsHeader.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/BkStyleEnum.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/CommonStatusEnum.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/DateIntervalEnum.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SubjectScopeType.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SystemModuleEnum.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/UserTypeEnum.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/functions/Preconditions.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocMapper.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocService.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocServiceImpl.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/SegmentIdGeneratorImpl.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/LeafAlloc.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Segment.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/SegmentBuffer.java create mode 100644 modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Status.java create mode 100644 modules/pipeline-ci-event/pom.xml create mode 100644 modules/pipeline-ci-event/src/main/java/cd/casic/pipeline/Main.java create mode 100644 modules/pipeline-ci-log/pom.xml create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/AppLogResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/BuildLogPrintResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/OpLogResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogPrintResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/UserLogResource.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/AppLogResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/BuildLogPrintResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/OpLogResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogPrintResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/UserLogResourceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/config/BuildLogPrinter.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/IndexMapper.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogStatusMapper.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogTahMapper.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogIndicesV2.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogStatus.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogSubTags.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/EndPageQueryLogs.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/LogLine.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/PageQueryLogs.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogLineNum.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogStatus.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogs.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/TaskBuildLogProperty.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessage.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessageWithLineNo.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/Ansi.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiAttribute.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiColor.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogErrorCodeEnum.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStatusEnum.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStorageMode.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogType.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/IEvent.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/ILogEvent.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogOriginEvent.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStatusEvent.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStorageEvent.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/CreateIndexBean.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/LogStorageBean.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogListenerService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogPrintService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogQueryService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/IndexService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogServiceImpl.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogStatusService.java create mode 100644 modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogTagService.java create mode 100644 modules/pipeline-ci-market/pom.xml create mode 100644 modules/pipeline-ci-market/src/main/java/cd/casic/pipeline/market/constant/StoreMessageCode.java create mode 100644 modules/pipeline-ci-process/pom.xml create mode 100644 modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/dal/package-info.java create mode 100644 modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/AESUtil.java create mode 100644 modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/CommonUtils.java create mode 100644 modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/LogUtils.java create mode 100644 modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/RetryUtils.java create mode 100644 modules/pipeline-ci-project/pom.xml create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/constant/ProjectConstants.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/controller/UserProjectResourceController.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dao/ProjectMapper.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dto/Project.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/AuthProjectCreateInfo.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/PipelineAsCodeSettings.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateExtInfo.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateInfo.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectProperties.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectVO.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ResourceRegisterInfo.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/SubjectScopeInfo.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/user/UserDeptDetail.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectApproveStatus.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectAuthSecrecyStatus.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectChannelCode.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectValidateType.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectExtService.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectPermissionService.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/UserProjectResourceService.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/BluekingProjectPermissionServiceImpl.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectExtServiceImpl.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectServiceImpl.java create mode 100644 modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/UserProjectResourceServiceImpl.java create mode 100644 modules/pipeline-ci-quality/pom.xml create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/api/ServiceQualityRuleResource.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/constants/QualityConstants.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/package-info.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckResult.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckSingleResult.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v2/ControlPointPosition.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/package-info.java create mode 100644 modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/request/BuildCheckParamsV3.java create mode 100644 modules/pipeline-ci-scm-repository/pom.xml create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/Main.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResource.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResourceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResource.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResourceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResource.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResourceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResource.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResourceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResource.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResourceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/GitConfig.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/P4Config.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/SVNConfig.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitTokenMapper.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitlabTokenMapper.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryRecordMapper.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryTGitTokenMapper.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitToken.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitlabToken.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryRecord.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryTGitToken.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitRepository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitlabRepository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeP4Repository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeSvnRepository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeTGitRepository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Credential.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/GithubRepository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/IScm.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Repository.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/RevisionInfo.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmFactory.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmOauthFactory.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitApi.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitOauthApi.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitUserInfo.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubBranch.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommit.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitAuthor.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitData.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubObject.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubTag.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubToken.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/oauth/GitToken.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitScmImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitlabScmImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeP4ScmImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeSvnScmImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeTGitScmImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeGitWebhookEvent.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeSvnRegion.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/GitHubTokenType.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepoAuthType.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryConfig.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryType.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryTypeNew.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RequestChannelTypeEnum.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/ScmType.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/TokenTypeEnum.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/CodeRepositoryServiceRegistrar.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/IGitOauthService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/code/CodeRepositoryService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/IGithubService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/GitOauthServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/RepositoryServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/GitServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IGitService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmOauthService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmOauthServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/ITGitService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenService.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenServiceImpl.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/GitUtils.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/HashUtil.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/RepositoryConfigUtils.java create mode 100644 modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/WebhookUtils.java create mode 100644 modules/pipeline-ci-ticket/pom.xml create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/ServiceCredentialResource.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/impl/ServiceCredentialResourceImpl.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/constant/TicketMessageCode.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dao/CredentialRecordMapper.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dataobject/CredentialRecord.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/enums/CredentialType.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Cert.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Credential.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/CredentialInfo.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialHelper.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialService.java create mode 100644 modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialServiceImpl.java diff --git a/.idea/$PROJECT_FILE$ b/.idea/$PROJECT_FILE$ new file mode 100644 index 0000000..58b7e3e --- /dev/null +++ b/.idea/$PROJECT_FILE$ @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/CopilotChatHistory.xml b/.idea/CopilotChatHistory.xml new file mode 100644 index 0000000..2b5234c --- /dev/null +++ b/.idea/CopilotChatHistory.xml @@ -0,0 +1,657 @@ + + + + + + \ No newline at end of file diff --git a/.idea/MarsCodeWorkspaceAppSettings.xml b/.idea/MarsCodeWorkspaceAppSettings.xml new file mode 100644 index 0000000..1706162 --- /dev/null +++ b/.idea/MarsCodeWorkspaceAppSettings.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..859bf4f --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..fc4eb2e --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8d66637 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..12fa056 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e20ddae --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/qaplug_profiles.xml b/.idea/qaplug_profiles.xml new file mode 100644 index 0000000..c6c6dc1 --- /dev/null +++ b/.idea/qaplug_profiles.xml @@ -0,0 +1,933 @@ + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dependencies/.flattened-pom.xml b/dependencies/.flattened-pom.xml index 142e1b3..bb565c9 100644 --- a/dependencies/.flattened-pom.xml +++ b/dependencies/.flattened-pom.xml @@ -27,6 +27,7 @@ 0.9.0 2.14.5 3.3.4 + 1.80 2.3.0 2.2.7 2.17.0 @@ -162,6 +163,41 @@ spring-boot-starter-websocket ${revision} + + cd.casic.boot + module-infra-api + ${revision} + + + cd.casic.boot + module-infra-biz + ${revision} + + + cd.casic.boot + module-system-api + ${revision} + + + cd.casic.boot + module-system-biz + ${revision} + + + cd.casic.pipeline + pipeline-ci-commons + ${revision} + + + cd.casic.pipeline + pipeline-ci-event + ${revision} + + + cd.casic.pipeline + pipeline-ci-log + ${revision} + io.github.mouzt bizlog-sdk @@ -492,6 +528,11 @@ mongo-plus-boot-starter ${anwena.version} + + org.bouncycastle + bcprov-jdk18on + ${bcprov-jdk18on.version} + diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 105c970..9ecc05d 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -33,7 +33,7 @@ 3.47.1.0 23.5.0.24.07 42.7.4 - + 2.0.8.3 2.3.1 @@ -74,6 +74,7 @@ 1.12.777 1.7.8 1.2.13 + 1.80 @@ -202,6 +203,25 @@ module-system-biz ${revision} + + + cd.casic.pipeline + pipeline-ci-commons + ${revision} + + + + cd.casic.pipeline + pipeline-ci-event + ${revision} + + + + cd.casic.pipeline + pipeline-ci-log + ${revision} + + io.github.mouzt @@ -585,7 +605,12 @@ ${anwena.version} - + + + org.bouncycastle + bcprov-jdk18on + ${bcprov-jdk18on.version} + diff --git a/framework/commons/pom.xml b/framework/commons/pom.xml index 61905b8..11d8903 100644 --- a/framework/commons/pom.xml +++ b/framework/commons/pom.xml @@ -61,6 +61,11 @@ provided + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + org.springdoc springdoc-openapi-starter-webmvc-api @@ -134,6 +139,11 @@ hutool-all + + com.squareup.okhttp3 + okhttp + + com.alibaba transmittable-thread-local @@ -149,6 +159,12 @@ oshi-core + + org.bouncycastle + bcprov-jdk18on + + + org.springframework.boot diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java b/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java index 4ce7656..371b0b6 100644 --- a/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java +++ b/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java @@ -2,6 +2,8 @@ package cd.casic.framework.commons.exception; import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; import cd.casic.framework.commons.exception.enums.ServiceErrorCodeRange; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; /** @@ -13,6 +15,8 @@ import lombok.Data; * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 */ @Data +@Builder +@AllArgsConstructor public class ErrorCode { /** @@ -24,9 +28,4 @@ public class ErrorCode { */ private final String msg; - public ErrorCode(Integer code, String message) { - this.code = code; - this.msg = message; - } - } diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java b/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java index 70dd1da..b375093 100644 --- a/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java +++ b/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java @@ -6,7 +6,7 @@ import cd.casic.framework.commons.exception.ErrorCode; /** * 全局错误码枚举 * 0-999 系统异常编码保留 - * + *

* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status * 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的 * 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。 @@ -39,4 +39,6 @@ public interface GlobalErrorCodeConstants { ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); + ErrorCode ID_DUPLICATION = new ErrorCode(1000, "ID重复"); + } diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java index 848bd47..b64e8f8 100644 --- a/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java @@ -38,7 +38,7 @@ public class CacheUtils { // 只阻塞当前数据加载线程,其他线程返回旧值 .refreshAfterWrite(duration) // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 - .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置 + .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); } /** diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java new file mode 100644 index 0000000..70a44d2 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java @@ -0,0 +1,89 @@ +package cd.casic.framework.commons.util.encrypt; + +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PKCS7Padding; +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.Base64; + +/** + * @author by mianbin + * @Classname AESUtil + * @Description 加密算法,后面加GM算法 + * @Date 2025/3/18 11:15 + */ +public class AESUtil { + private static final String AES = "AES"; + private static final Integer SEED = 256; + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + public static String decrypt(String key, String content) { + byte[] bytes = Base64.getDecoder().decode(content); + KeyParameter keyParameter = generateKeyParameter(key); + byte[] output = processData(false, keyParameter, bytes); + return Base64.getEncoder().encodeToString(output); + } + + public static byte[] decrypt(String key, byte[] content) { + KeyParameter keyParameter = generateKeyParameter(key); + return processData(false, keyParameter, content); + } + + public static String encrypt(String key, String content) { + byte[] bytes = content.getBytes(StandardCharsets.UTF_8); + KeyParameter keyParameter = generateKeyParameter(key); + byte[] output = processData(true, keyParameter, bytes); + return Base64.getEncoder().encodeToString(output); + } + + public static byte[] encrypt(String key, byte[] content) { + KeyParameter keyParameter = generateKeyParameter(key); + return processData(true, keyParameter, content); + } + + private static byte[] processData(boolean encrypt, KeyParameter keyParameter, byte[] bytes) { + PKCS7Padding blockCipherPadding = new PKCS7Padding(); + CBCBlockCipher blockCipher = new CBCBlockCipher(new AESEngine()); + PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(blockCipher, blockCipherPadding); + paddedBufferedBlockCipher.init(encrypt, keyParameter); + + byte[] output = new byte[paddedBufferedBlockCipher.getOutputSize(bytes.length)]; + int offset = paddedBufferedBlockCipher.processBytes(bytes, 0, bytes.length, output, 0); + int outputLength = 0; + try { + outputLength = paddedBufferedBlockCipher.doFinal(output, offset); + } catch (InvalidCipherTextException e) { + e.printStackTrace(); + } + return Arrays.copyOf(output, offset + outputLength); + } + + private static KeyParameter generateKeyParameter(String key) { + KeyGenerator keyGenerator = null; + SecureRandom secureRandom = null; + try { + keyGenerator = KeyGenerator.getInstance(AES); + secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + e.printStackTrace(); + } + + keyGenerator.init(SEED, secureRandom); + SecretKey secretKey = keyGenerator.generateKey(); + byte[] encoded = secretKey.getEncoded(); + return new KeyParameter(encoded); + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java new file mode 100644 index 0000000..34da2d1 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java @@ -0,0 +1,41 @@ +package cd.casic.framework.commons.util.encrypt; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Arrays; + +/** + * @author liubin + * @date 2023/10/10 14:00 + * @description + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DHKeyPair { + + private byte[] publicKey; + + private byte[] privateKey; + + @Override + public boolean equals(Object other) { + if (this == other) return true; + assert other != null; + if (this.getClass() != other.getClass()) return false; + + if (!Arrays.equals(publicKey,((DHKeyPair) other).publicKey)) return false; + if (!Arrays.equals(privateKey, ((DHKeyPair) other).privateKey)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(publicKey); + result = 31 * result + Arrays.hashCode(privateKey); + return result; + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java new file mode 100644 index 0000000..9a9cb26 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java @@ -0,0 +1,106 @@ +package cd.casic.framework.commons.util.encrypt; + +import lombok.SneakyThrows; + +import javax.crypto.*; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + + +public class DHUtil { + + private static final String KEY_ALGORITHM = "DH"; + private static final String KEY_PROVIDER = "BC"; + private static final String SECRET_ALGORITHM = "DES"; + + private static BigInteger p = new BigInteger("16560215747140417249215968347342080587", 16); + private static BigInteger g = new BigInteger("1234567890", 16); + + public static DHKeyPair initKey(){ + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, KEY_PROVIDER); + DHParameterSpec serverParam = new DHParameterSpec(p, g, 128); + keyPairGenerator.initialize(serverParam, new SecureRandom()); + //keyPairGenerator.initialize(KEY_SIZE); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + return new DHKeyPair(keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded()); + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException e) { + e.printStackTrace(); + } + return null; + } + + public static DHKeyPair initKey(byte[] partyAPublicKey) { + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(partyAPublicKey); + try { + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PrivateKey publicKey = keyFactory.generatePrivate(x509KeySpec); + + DHParameterSpec dhParameterSpec = ((DHPublicKey) publicKey).getParams(); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, KEY_PROVIDER); + keyPairGenerator.initialize(dhParameterSpec); +// keyPairGenerator.initialize(KEY_SIZE); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + return new DHKeyPair(keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded()); + } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException | InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + return null; + } + + public static byte[] encrypt(byte[] data, byte[] partAPublicKey, byte[] partBPrivateKey) { + byte[] key = getSecretKey(partAPublicKey, partBPrivateKey); + SecretKeySpec secretKey = new SecretKeySpec(key, SECRET_ALGORITHM); + try { + Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + return cipher.doFinal(data); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) { + e.printStackTrace(); + } + return null; + } + + public static byte[] decrypt(byte[] data, byte[] partBPublicKey, byte[] partAPrivateKey){ + byte[] key = getSecretKey(partBPublicKey, partAPrivateKey); + SecretKeySpec secretKey = new SecretKeySpec(key, SECRET_ALGORITHM); + Cipher cipher = null; + try { + cipher = Cipher.getInstance(secretKey.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + return cipher.doFinal(data); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) { + e.printStackTrace(); + } + return null; + } + + + @SneakyThrows + private static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) { + // 实例化密钥工厂 + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + // 初始化公钥 + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey); + // 产生公钥 + PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); + // 初始化私钥 + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey); + // 产生私钥 + PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); + // 实例化 + KeyAgreement keyAgree = KeyAgreement.getInstance(KEY_ALGORITHM, KEY_PROVIDER); + // 初始化 + keyAgree.init(priKey); + keyAgree.doPhase(pubKey, true); + // 生成本地密钥 + SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM); + return secretKey.getEncoded(); + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java new file mode 100644 index 0000000..304e926 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java @@ -0,0 +1,34 @@ +package cd.casic.framework.commons.util.generator; + +import java.util.List; + +/** + * @author mianbin + * @Classname UserTypeEnum + * @Description 业务id生成接口 + * @Date 2025/3/18 14:16 + */ +public interface IdGenerator { + + /** + * 生成id + * + * @param key 业务标识 + * @return 结果 + */ + Long get(String key); + + /** + * 初始化 + */ + boolean init(); + + /** + * 批量生成id + * + * @param key 业务标识 + * @param num id数量 + * @return id集合 + */ + List batchGenerateSegmentId(String key, Integer num); +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java new file mode 100644 index 0000000..9851ee4 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java @@ -0,0 +1,72 @@ +package cd.casic.framework.commons.util.http; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import cd.casic.framework.commons.exception.ServiceException; +import lombok.SneakyThrows; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.concurrent.TimeUnit; + +/** + * @author liubin + * @date 2023/10/11 14:02 + * @description + */ +public class OkhttpUtils { + + private static final long connectTimeout = 5L; + private static final long readTimeout = 30L; + private static final long writeTimeout = 30L; + + private static final TrustManager[] trustAnyCerts = new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }}; + + private static final OkHttpClient okHttpClient = new OkHttpClient.Builder() + .connectTimeout(connectTimeout, TimeUnit.SECONDS) + .readTimeout(readTimeout, TimeUnit.MINUTES) + .writeTimeout(writeTimeout, TimeUnit.MINUTES) + .sslSocketFactory(anySslSocketFactory(), (X509TrustManager) trustAnyCerts[0]) + .hostnameVerifier((s, sslSession) -> true) + .build(); + + private static SSLSocketFactory anySslSocketFactory(){ + try { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAnyCerts, new SecureRandom()); + return sslContext.getSocketFactory(); + } catch (Exception ignore){ + throw new ServiceException(); + } + } + + public static Response doHttp(Request request) { + return doHttp(okHttpClient, request); + } + + @SneakyThrows + private static Response doHttp(OkHttpClient okHttpClient, Request request) { + return okHttpClient.newCall(request).execute(); + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java new file mode 100644 index 0000000..b8bd4bc --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java @@ -0,0 +1,22 @@ +package cd.casic.framework.commons.util.reflect; + +import java.util.Collection; +import java.util.Map; + + +public class ReflectUtil { + + public static Boolean isNativeType(Object bean) { + return bean instanceof Integer || + bean instanceof Long || + bean instanceof Double || + bean instanceof Float || + bean instanceof Short || + bean instanceof Byte || + bean instanceof Boolean; + } + + public static Boolean isCollectionType(Object obj) { + return obj instanceof Map || obj instanceof Collection; + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java new file mode 100644 index 0000000..34731c8 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java @@ -0,0 +1,33 @@ +package cd.casic.framework.commons.util.retry; + +import lombok.SneakyThrows; + +/** + * @author by mianbin + * @Classname RetryUtils + * @Description TODO + * @Date 2025/3/18 11:28 + */ +public class RetryUtils { + @SneakyThrows + public static T execute(Action action, Integer retryTime, Long retryPeriodMills) { + try { + return action.execute(); + } catch (Throwable ignored) { + if (retryTime - 1 <= 0) { + return action.fail(ignored); + } + Thread.sleep(retryPeriodMills); + return execute(action, retryTime - 1, 500L); + } + } + + public interface Action { + + T execute(); + + default T fail(Throwable e) throws Throwable { + throw e; + } + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java index 3236d31..866781d 100644 --- a/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java @@ -63,7 +63,6 @@ public class StrUtils { /** * 移除字符串中,包含指定字符串的行 - * * @param content 字符串 * @param sequence 包含的字符串 * @return 移除后的字符串 diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java new file mode 100644 index 0000000..ef71548 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java @@ -0,0 +1,21 @@ +package cd.casic.framework.commons.util.validation; + +/** + * @author by mianbin + * @Classname ValidGroup + * @Description 验证组 + * @Date 2025/3/18 15:09 + */ +public interface ValidGroup { + interface Create extends ValidGroup { + } + + interface Update extends ValidGroup { + } + + interface Delete extends ValidGroup { + } + + interface Query extends ValidGroup { + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java new file mode 100644 index 0000000..56da864 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java @@ -0,0 +1,44 @@ +package cd.casic.framework.commons.util.watcher; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author by mianbin + * @Classname LogUtils + * @Description 流水线和watcher监控日志的工具类,放一起 + * @Date 2025/3/18 11:26 + */ +@Slf4j +public class LogUtils { + + /** + * 计算[watcher].createTime与当前时间的毫秒数的耗时在[warnThreshold]与[errorThreshold]之间, + * 会将[watcher]序列化为字符串并打印到WARN日志,当超出[errorThreshold]会打印ERROR日志。否则什么都不会打印 + */ + public static void printCostTimeWE(Watcher watcher, Long warnThreshold, Long errorThreshold) { + watcher.stop(); + long cost = System.currentTimeMillis() - watcher.getCreateTime(); + if (cost >= warnThreshold) { + if (cost > errorThreshold) { + log.error(watcher + " cost " + cost + " ms"); + } else { + log.warn(watcher + " cost " + cost + " ms"); + } + } + } + + public static void costTime(String message, Long startTime, Long warnThreshold, Long errorThreshold) { + long cost = System.currentTimeMillis() - startTime; + if (cost < warnThreshold) { + log.info(message + " cost " + cost + " ms"); + } else if (cost >= warnThreshold && cost < errorThreshold) { + log.warn(message + " cost " + cost + " ms"); + } else { + log.error(message + " cost " + cost + " ms"); + } + } + + public static void printCostTimeWE(Watcher watcher) { + printCostTimeWE(watcher, 1000L, 5000L); + } +} diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java new file mode 100644 index 0000000..29f79d5 --- /dev/null +++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java @@ -0,0 +1,82 @@ +package cd.casic.framework.commons.util.watcher; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StopWatch; + +/** + * @author by mianbin + * @Classname Watcher + * @Description 针对running值导致抛出异常的位置主动做了stop,并增加了一个全部耗时统计 + * @Date 2025/3/18 10:49 + */ +@Slf4j +public class Watcher extends StopWatch { + + @Getter + private long createTime = System.currentTimeMillis(); + + public Watcher(String id) { + super(id); + this.createTime = System.currentTimeMillis(); + } + + public long elapsed() { + return System.currentTimeMillis() - createTime; + } + + @Override + public void start() { + if (isRunning()) { + stop(); + } + super.start(); + } + + @Override + public void start(String taskName) { + if (isRunning()) { + stop(); + } + super.start(taskName); + } + + @Override + public String toString() { + if (isRunning()) { + stop(); + } + StringBuilder sb = new StringBuilder(shortSummary()); + for (TaskInfo task : this.getTaskInfo()) { + sb.append("|").append(task.getTaskName()).append("=").append(task.getTimeMillis()); + } + return sb.toString(); + } + + @Override + public String shortSummary() { + return "watcher|" + getId() + "|total=" + getTotalTimeMillis() + "|elapsed=" + elapsed(); + } + + @Override + public void stop() { + if (isRunning()) { + try { + super.stop(); + } catch (IllegalStateException ignored) { + } + } + } + + public void safeAround(String taskName, Runnable action) { + try { + this.start(taskName); + action.run(); + } catch (Exception e) { + log.warn(getId() + " , " + taskName, e); + } finally { + this.stop(); + } + } + +} diff --git a/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java b/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java index bc3a2db..3795719 100644 --- a/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java +++ b/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.context.annotation.Bean; @ConditionalOnProperty(prefix = "ops.tracer", value = "enable", matchIfMissing = true) public class OpsTracerAutoConfiguration { - // TODO 重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证阿里云短信 sdk + // TODO 重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证云短信 sdk // @Bean // public TracerProperties bizTracerProperties() { // return new TracerProperties(); diff --git a/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java b/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java index ee98c14..5376ed5 100644 --- a/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java +++ b/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java @@ -22,7 +22,7 @@ import java.time.LocalDateTime; */ @Data @Accessors(chain = true) -@JsonIgnoreProperties(value = "transMap") // 由于 Easy-Trans 会添加 transMap 属性,避免 Jackson 在 Spring Cache 反序列化报错 +@JsonIgnoreProperties(value = "transMap") public abstract class BaseDO implements Serializable, TransPojo { /** diff --git a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java index bfcc9e7..c40c0a4 100644 --- a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java +++ b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java @@ -1,5 +1,6 @@ package cd.casic.framework.redis.config; +import cd.casic.framework.redis.core.RedisTemplateUtils; import cn.hutool.core.util.ReflectUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -42,4 +43,9 @@ public class OpsRedisAutoConfiguration { return json; } + @Bean + public RedisTemplateUtils redisTemplateUtils() { + return new RedisTemplateUtils(); + } + } diff --git a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java new file mode 100644 index 0000000..53e6fb0 --- /dev/null +++ b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java @@ -0,0 +1,570 @@ +package cd.casic.framework.redis.core; + +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @author by mianbin + * @Classname RedisTemplateUtils + * @Description TODO + * @Date 2025/3/20 11:03 + */ +public class RedisTemplateUtils { + + @Resource + private RedisTemplate redisTemplate; + + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return Boolean.TRUE.equals(redisTemplate.hasKey(key)); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete((Collection) CollectionUtils.arrayToList(key)); + } + } + } + + //============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + //================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + //============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + return redisTemplate.opsForSet().remove(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + //===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + +} diff --git a/framework/spring-boot-starter-security/src/main/java/cd/casic/framework/security/core/handler/AuthenticationEntryPointImpl.java b/framework/spring-boot-starter-security/src/main/java/cd/casic/framework/security/core/handler/AuthenticationEntryPointImpl.java index 900e105..184c468 100644 --- a/framework/spring-boot-starter-security/src/main/java/cd/casic/framework/security/core/handler/AuthenticationEntryPointImpl.java +++ b/framework/spring-boot-starter-security/src/main/java/cd/casic/framework/security/core/handler/AuthenticationEntryPointImpl.java @@ -18,7 +18,7 @@ import static cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstant * * 补充:Spring Security 通过 {@link ExceptionTranslationFilter#sendStartAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, AuthenticationException)} 方法,调用当前类 * - * @author ruoyi + * mianbin modified from yudao */ @Slf4j @SuppressWarnings("JavadocReference") // 忽略文档引用报错 diff --git a/framework/spring-boot-starter-web/src/main/java/cd/casic/framework/apilog/core/enums/OperateTypeEnum.java b/framework/spring-boot-starter-web/src/main/java/cd/casic/framework/apilog/core/enums/OperateTypeEnum.java index 78b1b9a..c6eceec 100644 --- a/framework/spring-boot-starter-web/src/main/java/cd/casic/framework/apilog/core/enums/OperateTypeEnum.java +++ b/framework/spring-boot-starter-web/src/main/java/cd/casic/framework/apilog/core/enums/OperateTypeEnum.java @@ -6,7 +6,7 @@ import lombok.Getter; /** * 操作日志的操作类型 * - * @author ruoyi + * mianbin modified from yudao */ @Getter @AllArgsConstructor diff --git a/modules/module-system-api/src/main/java/cd/casic/module/system/enums/ErrorCodeConstants.java b/modules/module-system-api/src/main/java/cd/casic/module/system/enums/ErrorCodeConstants.java index e03c2f3..bbffcb4 100644 --- a/modules/module-system-api/src/main/java/cd/casic/module/system/enums/ErrorCodeConstants.java +++ b/modules/module-system-api/src/main/java/cd/casic/module/system/enums/ErrorCodeConstants.java @@ -73,11 +73,6 @@ public interface ErrorCodeConstants { // ========== 通知公告 1-002-008-000 ========== ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在"); - // ========== 短信渠道 1-002-011-000 ========== - ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在"); - ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择"); - ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板"); - // ========== 短信模板 1-002-012-000 ========== ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在"); ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板"); @@ -112,16 +107,12 @@ public interface ErrorCodeConstants { ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用"); ErrorCode TENANT_PACKAGE_NAME_DUPLICATE = new ErrorCode(1_002_016_003, "已经存在该名字的租户套餐"); - // ========== 社交用户 1-002-018-000 ========== - ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); - ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); + // ========== 单点登录 1-002-018-000 ========== + ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "第三方授权失败,原因是:{}"); + ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "第三方授权失败,找不到对应的用户"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败"); - ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败"); - ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在"); - ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置"); + ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "第三方客户端不存在"); + ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "第三方客户端已存在配置"); // ========== OAuth2 客户端 1-002-020-000 ========= diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/DeptDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/DeptDO.java index b21d5c3..2c70e20 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/DeptDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/DeptDO.java @@ -12,8 +12,6 @@ import lombok.experimental.Accessors; /** * 部门表 - * - * @author ruoyi * @author mianbin modified from yudao */ @TableName("system_dept") diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/PostDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/PostDO.java index 40e4a3b..1708b3c 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/PostDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/PostDO.java @@ -12,7 +12,7 @@ import lombok.experimental.Accessors; /** * 岗位表 * - * @author ruoyi + * @author mianbin modified from yudao */ @TableName("system_post") @KeySequence("system_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/UserPostDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/UserPostDO.java index d43e226..6938877 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/UserPostDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dept/UserPostDO.java @@ -11,8 +11,6 @@ import lombok.experimental.Accessors; /** * 用户和岗位关联 - * - * @author ruoyi */ @TableName("system_user_post") @KeySequence("system_user_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictDataDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictDataDO.java index e75ffe4..4cb0725 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictDataDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictDataDO.java @@ -10,7 +10,7 @@ import lombok.experimental.Accessors; /** * 字典数据表 * - * @author ruoyi + * @author mianbin modified from yudao */ @TableName("system_dict_data") @KeySequence("system_dict_data_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictTypeDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictTypeDO.java index 50d7d44..738ef70 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictTypeDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/dict/DictTypeDO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; /** * 字典类型表 * - * @author ruoyi + * mianbin modified from yudao */ @TableName("system_dict_type") @KeySequence("system_dict_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/mail/MailAccountDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/mail/MailAccountDO.java index 5f89eda..7b0cbc5 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/mail/MailAccountDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/mail/MailAccountDO.java @@ -13,8 +13,7 @@ import lombok.experimental.Accessors; * * 用途:配置发送邮箱的账号 * - * @author wangjingyi - * @since 2022-03-21 + * @author mianbin modified from yudao */ @TableName(value = "system_mail_account", autoResultMap = true) @KeySequence("system_mail_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/notice/NoticeDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/notice/NoticeDO.java index e5bf832..adc9f09 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/notice/NoticeDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/notice/NoticeDO.java @@ -12,7 +12,7 @@ import lombok.experimental.Accessors; /** * 通知公告表 * - * @author ruoyi + * mianbin modified from yudao */ @TableName("system_notice") @KeySequence("system_notice_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/MenuDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/MenuDO.java index de510e9..d6e9177 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/MenuDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/MenuDO.java @@ -13,7 +13,7 @@ import lombok.experimental.Accessors; /** * 菜单 DO * - * @author ruoyi + * mianbin modified from yudao */ @TableName("system_menu") @KeySequence("system_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleDO.java index 027335b..c960b48 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleDO.java @@ -19,7 +19,7 @@ import java.util.Set; /** * 角色 DO * - * @author ruoyi + * mianbin modified from yudao */ @TableName(value = "system_role", autoResultMap = true) @KeySequence("system_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleMenuDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleMenuDO.java index 1014102..13935d9 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleMenuDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/RoleMenuDO.java @@ -11,7 +11,7 @@ import lombok.experimental.Accessors; /** * 角色和菜单关联 * - * @author ruoyi + * mianbin modified from yudao */ @TableName("system_role_menu") @KeySequence("system_role_menu_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/UserRoleDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/UserRoleDO.java index 2899aee..052ed14 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/UserRoleDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/permission/UserRoleDO.java @@ -11,7 +11,7 @@ import lombok.experimental.Accessors; /** * 用户和角色关联 * - * @author ruoyi + * mianbin modified from yudao */ @TableName("system_user_role") @KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/tenant/TenantDO.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/tenant/TenantDO.java index 2016089..00782c4 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/tenant/TenantDO.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/dal/dataobject/tenant/TenantDO.java @@ -16,7 +16,7 @@ import java.time.LocalDateTime; * @author mianbin modified from yudao */ @TableName(value = "system_tenant", autoResultMap = true) -@KeySequence("system_tenant_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@KeySequence("system_tenant_seq") @Data @Accessors(chain = true) @EqualsAndHashCode(callSuper = true) diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataService.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataService.java index 8107158..80152d0 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataService.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataService.java @@ -13,7 +13,7 @@ import java.util.List; /** * 字典数据 Service 接口 * - * @author ruoyi + * mianbin modified from yudao */ public interface DictDataService { diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataServiceImpl.java b/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataServiceImpl.java index 42419ec..5e74a18 100644 --- a/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataServiceImpl.java +++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/service/dict/DictDataServiceImpl.java @@ -28,7 +28,7 @@ import static cd.casic.module.system.enums.ErrorCodeConstants.*; /** * 字典数据 Service 实现类 * - * @author ruoyi + * mianbin modified from yudao */ @Service @Slf4j diff --git a/modules/pipeline-ci-commons/pom.xml b/modules/pipeline-ci-commons/pom.xml new file mode 100644 index 0000000..7c81ebb --- /dev/null +++ b/modules/pipeline-ci-commons/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-commons + ${revision} + + + 流水线process、流水线engine、流水线work、资源管理层、环境管理、agent、构建调度、项目管理、代码库、凭证、扩展Plugin、日志、流水线外设需要的commons + + + + + cd.casic.boot + commons + + + cd.casic.boot + spring-boot-starter-mybatis + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/BaseConstant.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/BaseConstant.java new file mode 100644 index 0000000..e26e7d0 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/BaseConstant.java @@ -0,0 +1,19 @@ +package cd.casic.pipeline.commons.constant; + +/** + * @Classname BaseConstant + * @Description 标志位 + * @Date 2025/3/18 10:00 + * @author mianbin + */ +public class BaseConstant { + /** + * 已删 + */ + public static final Integer DELETED = 1; + + /** + * 未删 + */ + public static final Integer NOT_DELETED = 0; +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonConstants.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonConstants.java new file mode 100644 index 0000000..78ec33e --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonConstants.java @@ -0,0 +1,136 @@ +package cd.casic.pipeline.commons.constant; + +/** + * @Classname CommonConstants + * @Description TODO + * @Date 2025/3/18 10:02 + * @author mianbin + */ +public class CommonConstants { + public static final String BCI_CODE_PREFIX = "BCI_CODE_"; + public static final String DEVOPS = "DevOps"; + public static final Integer NUM_ONE = 1; + public static final Integer NUM_TWO = 2; + public static final Integer NUM_THREE = 3; + public static final Integer NUM_FOUR = 4; + public static final Integer NUM_FIVE = 5; + public static final Integer NUM_SIX = 6; + public static final Integer NUM_SEVEN = 7; + public static final Integer NUM_EIGHT = 8; + public static final Integer NUM_NINE = 9; + public static final String INIT_VERSION = "1.0.0"; // 初始化版本 + public static final String BEGIN = "begin"; // 开始 + public static final String EDIT = "edit"; // 提交信息 + public static final String COMMIT = "commit"; // 提交 + public static final String BUILD = "build"; // 构建 + public static final String CHECK = "check"; // 验证 + public static final String TEST = "test"; // 测试 + public static final String CODECC = "codecc"; // 代码检查 + public static final String APPROVE = "approve"; // 审核 + public static final String END = "end"; // 结束 + public static final String SUCCESS = "success"; // 成功 + public static final String UNDO = "undo"; // 未执行 + public static final String DOING = "doing"; // 执行中 + public static final String FAIL = "fail"; // 失败 + public static final String ONLINE = "online"; // 上线 + public static final String TEST_ENV_PREPARE = "testEnvPrepare"; // 准备测试环境 + public static final String ING = "ing"; // 中 + public static final String LATEST = "latest"; // 最新 + public static final String DEVELOP = "develop"; // 开发 + public static final String DEPLOY = "deploy"; // 部署 + public static final String SECURITY = "security"; // 安全 + public static final String NORMAL = "normal"; // 正常 + public static final String EXCEPTION = "exception"; // 异常 + public static final String REQUIRED = "required"; // 必选 + public static final String MIN_LENGTH = "minLength"; // 最小长度 + public static final String MAX_LENGTH = "maxLength"; // 最大长度 + public static final String DEFAULT = "default"; // 默认 + public static final String JAVA = "java"; // java + public static final String PYTHON = "python"; // python + public static final String NODEJS = "nodejs"; // nodejs + public static final String GOLANG = "golang"; // golang + public static final String JS = "js"; // js + public static final String PATTERN_STYLE = "patternStyle"; // 正则表达式规则 + public static final String MESSAGE = "message"; // 提示信息 + public static final String STATIC = "static"; // 静态资源 + public static final String NAME = "name"; // 名称 + public static final String FAIL_NUM = "failNum"; // 失败数量 + public static final String VERSION = "version"; // 版本号 + public static final String TYPE = "type"; // 类型 + public static final String OUTPUT_DESC = "description"; // 插件输出字段描述 + public static final String COMPONENT = "component"; // 组件 + public static final String PIPELINE_URL = "pipelineUrl"; // 流水线链接 + public static final String ARTIFACT = "artifact"; // 构件 + public static final String REPORT = "report"; // 报告 + public static final String VALUE = "value"; // 值 + public static final String MULTIPLE_SELECTOR = "multiple"; // 多选 + public static final String SINGLE_SELECTOR = "single"; // 单选 + public static final String OPTIONS = "options"; // 可选项 + public static final String LABEL = "label"; // 标签 + public static final String NO_LABEL = "noLabel"; // 无标题 + public static final String URL = "url"; // url链接 + public static final String PATH = "path"; // 路径 + public static final String ARTIFACTORY_TYPE = "artifactoryType"; // 归档仓库类型 + public static final String REPORT_TYPE = "reportType"; // 报告类型 + public static final String DATA = "data"; // 数据 + public static final String STRING = "string"; // 字符串 + public static final String LATEST_MODIFIER = "latestModifier"; // 最近修改人 + public static final String LATEST_UPDATE_TIME = "latestUpdateTime"; // 最近修改时间 + public static final String LATEST_EXECUTOR = "latestExecutor"; // 最近执行人 + public static final String LATEST_EXECUTE_TIME = "latestExecuteTime"; // 最近执行时间 + public static final String DANG = "dang"; // 当 + public static final String AND = "and"; // 和 + public static final String OR = "or"; // 或 + public static final String TIMETOSELECT = "timetoSelect"; // 时必选 + public static final String MASTER = "master"; // 主干 + public static final String SYSTEM = "system"; // 系统 + public static final String BUILD_RUNNING = "buildRunning"; // 运行中 + public static final String BUILD_QUEUE = "buildQueue"; // 构建排队中 + public static final String BUILD_REVIEWING = "buildReviewing"; // 构建待审核 + public static final String BUILD_STAGE_SUCCESS = "buildStageSuccess"; // 构建阶段性完成 + public static final String BUILD_COMPLETED = "buildCompleted"; // 构建完成 + public static final String BUILD_CANCELED = "buildCanceled"; // 构建已取消 + public static final String BUILD_FAILED = "buildFailed"; // 构建失败 + public static final String ID = "id"; // id + public static final String STATUS = "status"; // 状态 + public static final String EXECUTE_COUNT = "executeCount"; + public static final String DEFAULT_LOCALE_LANGUAGE = "zh_CN"; // 默认语言信息 + public static final String REQUEST_CHANNEL = "BK_CI_REQUEST_CHANNEL"; // 请求渠道 + public static final String BK_CREATE = "bkCreate"; // 创建 + public static final String BK_REVISE = "bkRevise"; // 修改 + public static final String KEY_START_TIME = "startTime"; + public static final String KEY_END_TIME = "endTime"; + public static final String KEY_CHANNEL = "channel"; + public static final String HIDDEN_SYMBOL = "******"; + public static final String KEY_DEFAULT = "default"; + public static final String KEY_INPUT = "vuex-input"; + public static final String KEY_TEXTAREA = "vuex-textarea"; + public static final String KEY_CODE_EDITOR = "atom-ace-editor"; + public static final String KEY_OS = "os"; + public static final String KEY_SUMMARY = "summary"; + public static final String KEY_DOCSLINK = "docsLink"; + public static final String KEY_DESCRIPTION = "description"; + public static final String KEY_WEIGHT = "weight"; + public static final String KEY_ALL = "all"; + public static final String API_ACCESS_TOKEN_PROPERTY = "access_token"; + public static final String TEMPLATE_ACROSS_INFO_ID = "devops_template_across_info_id"; + public static final String KEY_OS_NAME = "osName"; + public static final String KEY_OS_ARCH = "osArch"; + public static final String KEY_INVALID_OS_INFO = "invalidOsInfo"; + public static final String KEY_VALID_OS_NAME_FLAG = "validOsNameFlag"; + public static final String KEY_VALID_OS_ARCH_FLAG = "validOsArchFlag"; + public static final String KEY_SCRIPT = "script"; + public static final String KEY_COMMIT_ID = "commitId"; + public static final String KEY_BRANCH = "branch"; + public static final String KEY_REPOSITORY_HASH_ID = "repositoryHashId"; + public static final String KEY_REPOSITORY_PATH = "repositoryPath"; + public static final String KEY_VERSION = "version"; + public static final String KEY_VERSION_NAME = "versionName"; + public static final String KEY_UPDATED_TIME = "updatedTime"; + public static final String KEY_DEFAULT_LOCALE_LANGUAGE = "defaultLocaleLanguage"; + public static final String BK_BUILD_ENV_START_FAILED = "BuildEnvStartFailed"; // 构建环境启动失败 + public static final String BK_START_PULL_IMAGE = "StartPullImage"; // 开始拉取镜像,镜像名称: + public static final String BK_PULLING_IMAGE = "PullingImage"; // 正在拉取镜像,第{0}层,进度:{1} + public static final String BK_PUSH_IMAGE = "PushImage"; // 正在推送镜像,第{0}层,进度:{1} + public static final String BK_HUMAN_SERVICE = "HumanService"; // 人工服务 +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonMessageCode.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonMessageCode.java new file mode 100644 index 0000000..8ef614a --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/CommonMessageCode.java @@ -0,0 +1,222 @@ +package cd.casic.pipeline.commons.constant; + +/** + * @Classname CommonMessageCode + * @Description + * * 流水线微服务模块请求返回状态码 + * * 返回码制定规则(0代表成功,为了兼容历史接口的成功状态都是返回0): + * * 1、返回码总长度为7位, + * * 2、前2位数字代表系统名称(如21代表平台) + * * 3、第3位和第4位数字代表微服务模块(00:common-公共模块 01:process-流水线 02:artifactory-版本仓库 03:dispatch-分发 04:dockerhost-docker机器 + * * 05:environment-环境 06:experience-版本体验 07:image-镜像 08:log-日志 09:measure-度量 10:monitoring-监控 11:notify-通知 + * * 12:openapi-开放api接口 13:plugin-插件 14:quality-质量红线 15:repository-代码库 16:scm-软件配置管理 17:support-支撑服务 + * * 18:ticket-证书凭据 19:project-项目管理 20:store-商店 21: auth-权限 22:sign-签名服务 23:metrics-度量服务 24:external-外部 + * * 25:prebuild-预建 26: dispatcher-kubernetes 27:buildless 28: lambda 29: stream 30: worker 31: dispatcher-docker + * * 32: remotedev) + * * 4、最后3位数字代表具体微服务模块下返回给客户端的业务逻辑含义(如001代表系统服务繁忙,建议一个模块一类的返回码按照一定的规则制定)remotedev + * * 5、系统公共的返回码写在CommonMessageCode这个类里面,具体微服务模块的返回码写在相应模块的常量类里面 + * @Date 2025/3/18 10:08 + * @Created by mianbin + */ +public class CommonMessageCode { + public static final String MSG_CODE_ROLE_PREFIX = "MSG_CODE_ROLE_PREFIX_"; // 角色国际化前缀 + public static final String MSG_CODE_PERMISSION_PREFIX = "MSG_CODE_PERMISSION_PREFIX_";// 操作权限国际化前缀 + public static final String SUCCESS = "0"; // 成功 + public static final Integer OAUTH_DENERD = 418; // 自定义状态码, 未进行oauth认证 + public static final String SYSTEM_ERROR = "2100001"; // 系统内部繁忙,请稍后再试 + public static final String PARAMETER_IS_NULL = "2100002";// 参数{0}不能为空 + public static final String PARAMETER_IS_EXIST = "2100003";// 参数值{0}已经存在系统,请换一个再试 + public static final String PARAMETER_IS_INVALID = "2100004";// 参数值{0}为非法数据 + public static final String OAUTH_TOKEN_IS_INVALID = "2100005";// 无效的token,请先oauth认证 + public static final String PERMISSION_DENIED = "2100006";// 无权限{0} + public static final String ERROR_SERVICE_NO_FOUND = "2100007";// "找不到任何有效的{0}服务提供者" + public static final String ERROR_SERVICE_INVOKE_FAILURE = "2100008";// "服务调用失败:{0},uniqueId={1}" + public static final String ERROR_INVALID_CONFIG = "2100009";// "配置不可用:{0},uniqueId={1}" + public static final String ERROR_REST_EXCEPTION_COMMON_TIP = "2100010";// 接口访问出现异常,请联系助手或稍后再重试 + public static final String ERROR_CLIENT_REST_ERROR = "2100011";// 用户请求不合法,参数或方法错误,请咨询助手 + public static final String ERROR_PROJECT_FEATURE_NOT_ACTIVED = "2100012";// 项目[{0}]未开通该功能 + public static final String ERROR_INVALID_PARAM_ = "2100013";// 无效参数: {0} + public static final String ERROR_NEED_PARAM_ = "2100014";// 缺少参数: {0} + public static final String PARAMETER_VALIDATE_ERROR = "2100015";// {0}参数校验错误: {1} + public static final String ERROR_SERVICE_NO_AUTH = "2100016";// 无访问服务的权限 + public static final String ERROR_QUERY_NUM_TOO_BIG = "2100017";// 查询的数量超过系统规定的值:{0},请调整查询条件或咨询助手 + public static final String ERROR_QUERY_TIME_RANGE_TOO_LARGE = "2100018";// 查询的时间范围跨度最大,最长时间范围跨度不能超过{0}天 + public static final String ERROR_HTTP_RESPONSE_BODY_TOO_LARGE = "2100019";// http请求返回体太大 + public static final String PERMISSION_DENIED_FOR_APP = "2100020";// APP的无权限{0} + public static final String ERROR_SENSITIVE_API_NO_AUTH = "2100021";// 无敏感API访问权限 + public static final String PARAMETER_LENGTH_TOO_LONG = "2100022";// 参数长度不能超过{0}个字符 + public static final String PARAMETER_LENGTH_TOO_SHORT = "2100023";// 参数长度不能小于{0}个字符 + public static final String PARAMETER_ILLEGAL_ERROR = "2100024";// {0}参数非法错误: {1} + public static final String PARAMETER_EXPIRED_ERROR = "2100025";// {0}token过期错误: {1} + public static final String PARAMETER_SECRET_ERROR = "2100026";// {0}密钥配置错误: {1} + public static final String PARAMETER_IS_EMPTY = "2100027";// 参数不能为空 + public static final String ERROR_QUERY_TIME_RANGE_ERROR = "2100028";// 查询的时间范围跨度错误 + public static final String SERVICE_NOT_EXIST = "2100029";// 父服务不存在异常 + + public static final String ILLEGAL_GITCI_SERVICE_IMAGE_FORMAT = "2100030";// GITCI Service镜像格式非法 + public static final String THIRD_PARTY_SERVICE_DEVCLOUD_EXCEPTION = "2100031";// 第三方服务-DEVCLOUD 异常,请联系8006排查,异常信息 - + public static final String CREATE_CONTAINER_INTERFACE_EXCEPTION = "2100032";// 创建容器接口异常 + public static final String CREATE_CONTAINER_RETURNS_FAILED = "2100033";// 创建容器接口返回失败 + public static final String CREATE_CONTAINER_TIMED_OUT = "2100034";// 创建容器接口超时 + public static final String OPERATION_CONTAINER_INTERFACE_EXCEPTION = "2100035";// 操作容器接口异常 + public static final String OPERATION_CONTAINER_RETURNED_FAILURE = "2100036";// 操作容器接口返回失败 + public static final String OPERATION_CONTAINER_TIMED_OUT = "2100037";// 操作容器接口超时 + public static final String GET_STATUS_INTERFACE_EXCEPTION = "2100038";// 获取容器状态接口异常 + public static final String GET_STATUS_TIMED_OUT = "2100039";// 获取容器状态接口超时 + public static final String CREATE_MIRROR_INTERFACE_EXCEPTION = "2100040";// 创建镜像接口异常 + public static final String CREATE_MIRROR_INTERFACE_RETURNED_FAILURE = "2100041";// 创建镜像接口返回失败 + public static final String CREATE_MIRROR_INTERFACE_EXCEPTION_NEW = "2100042";// 创建镜像新版本接口异常 + public static final String NEW_MIRROR_INTERFACE_RETURNED_FAILURE = "2100043";// 创建镜像新版本接口返回失败 + public static final String TASK_STATUS_INTERFACE_EXCEPTION = "2100044";// 获取TASK状态接口异常 + public static final String TASK_STATUS_TIMED_OUT = "2100045";// 获取TASK状态接口超时 + public static final String GET_WEBSOCKET_INTERFACE_EXCEPTION = "2100046";// 获取websocket接口异常 + public static final String PARAMETER_CANNOT_EMPTY_ALL = "2100047";// 参数不能全部为空 + public static final String USERS_EXCEEDS_THE_LIMIT = "2100048";// 授权用户数越界:{0} + public static final String FAILED_TO_QUERY_GSE_AGENT_STATUS = "2100049";// 查询 Gse Agent 状态失败 + public static final String FAILED_TO_GET_AGENT_STATUS = "2100050";// 获取agent状态失败 + public static final String FAILED_TO_GET_CMDB_NODE = "2100051";// 获取 CMDB 节点失败 + public static final String FAILED_TO_GET_CMDB_LIST = "2100052";// 获取CMDB列表失败 + public static final String STAGES_AND_STEPS_CANNOT_EXIST_BY_SIDE = "2100053";// stages和steps不能并列存在! + + public static final String USER_NOT_PERMISSIONS_OPERATE_PIPELINE = "2100054";// 用户({0})无权限在工程({1})下{2}流水线{3} + public static final String USER_NOT_HAVE_PROJECT_PERMISSIONS = "2100055";// 用户 {0}无项目{1}权限 + public static final String UNABLE_GET_PIPELINE_JOB_STATUS = "2100056";// 无法获取流水线JOB状态,构建停止 + public static final String JOB_BUILD_STOPS = "2100057";// 流水线JOB已经不再运行,构建停止 + public static final String PIPELINE_NAME_OCCUPIED = "2100058";// 流水线名称已被他人使用 + public static final String INTERNAL_DEPENDENCY_SERVICE_EXCEPTION = "2100059";// 内部依赖服务异常 + public static final String PUBLIC_BUILD_RESOURCE_POOL_NOT_EXIST = "2100060";// 公共构建资源池不存在,请检查yml配置. + public static final String ERROR_LANGUAGE_IS_NOT_SUPPORT = "2100061";// 该语言蓝盾目前不支持,蓝盾目前支持的语言标识为:{0} + public static final String INIT_SERVICE_LIST_ERROR = "2100062";// 初始化服务列表异常问题 + public static final String FILE_NOT_EXIST = "2100063";// 文件{0}不存在 + public static final String USER_ACCESS_CHECK_FAIL = "2100064";// Gitlab access token 不正确 + + public static final String GITLAB_TOKEN_EMPTY = "2100065";// GitLab Token为空 + public static final String GITLAB_HOOK_URL_EMPTY = "2100066";// GitLab hook url为空 + public static final String GITLAB_TOKEN_FAIL = "2100067";// GitLab Token不正确 + public static final String GIT_TOKEN_FAIL = "2100068";// Git Token不正确 + public static final String SERCRT_EMPTY = "2100069";// GIT 私钥为空 + public static final String GIT_SERCRT_WRONG = "2100070";// Git 私钥不对 + public static final String PWD_EMPTY = "2100071";// 用户密码为空 + public static final String USER_NAME_EMPTY = "2100072";// 用户名为空 + public static final String GITLAB_INVALID = "2100073";// 无效的GITLAB仓库 + public static final String GIT_TOKEN_WRONG = "2100074";// Git Token 不正确 + public static final String GIT_LOGIN_FAIL = "2100075";// Git 用户名或者密码不对 + public static final String GIT_TOKEN_EMPTY = "2100076";// Git Token为空 + public static final String GIT_HOOK_URL_EMPTY = "2100077";// Git hook url为空 + public static final String TGIT_LOGIN_FAIL = "2100078";// TGit 用户名或者密码不对 + public static final String TGIT_TOKEN_EMPTY = "2100079";// TGit Token 不正确 + public static final String TGIT_SECRET_WRONG = "2100080";// TGit 私钥不对 + public static final String SVN_SECRET_OR_PATH_ERROR = "2100081";// SVN 私钥不正确 或者 SVN 路径没有权限 + public static final String SVN_CREATE_HOOK_FAIL = "2100082";// 添加SVN WEB hook 失败 + public static final String LOCK_FAIL = "2100083";// lock失败 + public static final String UNLOCK_FAIL = "2100084";// unlock失败 + public static final String GIT_REPO_PEM_FAIL = "2100085";// 代码仓库访问未授权 + public static final String CALL_REPO_ERROR = "2100086";// 代码仓库访问异常 + public static final String P4_USERNAME_PASSWORD_FAIL = "2100087";// p4用户名密码错误 + public static final String PARAM_ERROR = "2100088";// 参数错误 + public static final String AUTH_FAIL = "2100089";// {0}认证失败 + public static final String ACCOUNT_NO_OPERATION_PERMISSIONS = "2100090";// 账户没有{0}的权限 + public static final String REPO_NOT_EXIST_OR_NO_OPERATION_PERMISSION = "2100091";// {0}仓库不存在或者是账户没有该项目{1}的权限 + public static final String GIT_INTERFACE_NOT_EXIST = "2100092";// {0}平台没有{1}的接口 + public static final String GIT_CANNOT_OPERATION = "2100093";// {0}平台{1}操作不能进行 + public static final String WEBHOOK_LOCK_UNLOCK_FAIL = "2100094";// unlock webhooklock失败,请确认token是否已经配置 + public static final String COMMIT_CHECK_ADD_FAIL = "2100095";// Commit Check添加失败,请确保该代码库的凭据关联的用户对代码库有Developer权限 + public static final String ADD_MR_COMMENTS_FAIL = "2100096";// 添加MR的评论失败,请确保该代码库的凭据关联的用户对代码库有Developer权限 + public static final String WEBHOOK_ADD_FAIL = "2100097";// Webhook添加失败,请确保该代码库的凭据关联的用户对代码库有{0}权限 + public static final String WEBHOOK_UPDATE_FAIL = "2100098";// Webhook更新失败,请确保该代码库的凭据关联的用户对代码库有Developer权限 + public static final String ENGINEERING_REPO_UNAUTHORIZED = "2100099";// 工程仓库访问未授权 + public static final String ENGINEERING_REPO_NOT_EXIST = "2100100";// 工程仓库不存在 + public static final String ENGINEERING_REPO_CALL_ERROR = "2100101";// 工程仓库访问异常 + public static final String NOT_MEMBER_AND_NOT_OPEN_SOURCE = "2100102";// 非项目成员且项目为非开源项目 + // 2100108 + public static final String USER_NO_PIPELINE_PERMISSION = "2100108";// 流水线: 用户无{0}权限 + public static final String SERVICE_COULD_NOT_BE_ANALYZED = "2100109";// 无法根据接口"{0}"分析所属的服务 + public static final String RETURNED_RESULT_COULD_NOT_BE_PARSED = "2100110";// 内部服务返回结果无法解析 status:{0} body:{1} + public static final String SERVICE_PROVIDER_NOT_FOUND = "2100111";// 找不到任何有效的{0}【{1}】服务提供者 + public static final String ILLEGAL_JOB_TYPE = "2100112";// 非法的job类型! + public static final String ERROR_YAML_FORMAT_EXCEPTION = "2100113";// {0} 中 {1} 格式有误,应为 {2}, error message:{3} + public static final String ERROR_YAML_FORMAT_EXCEPTION_CHECK_STAGE_LABEL = "2100114";// 请核对Stage标签是否正确 + public static final String ERROR_YAML_FORMAT_EXCEPTION_LENGTH_LIMIT_EXCEEDED = "2100115";// "{0} job.id 超过长度限制64 {1}}" + public static final String ERROR_YAML_FORMAT_EXCEPTION_NEED_PARAM = "2100116";// {0} 中的step必须包含uses或run或checkout! + public static final String ERROR_YAML_FORMAT_EXCEPTION_SERVICE_IMAGE_FORMAT_ILLEGAL = "2100117";// STREAM Service镜像格式非法 + public static final String ERROR_YAML_FORMAT_EXCEPTION_STEP_ID_UNIQUENESS = "2100118";// 请确保step.id唯一性!({0}) + public static final String BUILD_RESOURCE_NOT_EXIST = "2100119";// {0}构建资源不存在,请检查yml配置. + public static final String ERROR_YAML_FORMAT_EXCEPTION_ENV_QUANTITY_LIMIT_EXCEEDED = "2100120";// {0}配置Env数量超过100限制! + // {0}Env单变量{1}长度超过{2}字符!({3}) + public static final String ERROR_YAML_FORMAT_EXCEPTION_ENV_VARIABLE_LENGTH_LIMIT_EXCEEDED = "2100121"; + + public static final String BK_CONTAINER_TIMED_OUT = "bkContainerTimedOut";// 创建容器超时 + public static final String BK_CREATION_FAILED_EXCEPTION_INFORMATION = "bkCreationFailedExceptionInformation";// 创建失败,异常信息 + + public static final String BK_FILE_NAME = "bkFileName";// 文件名 + public static final String BK_BELONG_TO_THE_PROJECT = "bkBelongToTheProject";// 所属项目 + public static final String BK_OPERATING = "bkOperating";// 操作 + public static final String BK_PUSH_FROM_BLUE_SHIELD_DEVOPS_PLATFORM = "bkPushFromBlueShieldDevopsPlatform";// 来自蓝盾DevOps平台的推送 + public static final String BK_TABLE_CONTENTS = "bkTableContents";// 表格内容 + public static final String BK_PLEASE_FEEL_TO_CONTACT_BLUE_SHIELD_ASSISTANT = "bkPleaseFeelToContactBlueShieldAssistant"; + // 如有任何问题,可随时联系蓝盾助手 + public static final String BK_ETH1_NETWORK_CARD_IP_EMPTY = "bkEth1NetworkCardIpEmpty";// eth1 网卡Ip为空,因此,获取eth0的网卡ip + public static final String BK_LOOPBACK_ADDRESS_OR_NIC_EMPTY = "bkLoopbackAddressOrNicEmpty";// loopback地址或网卡名称为空 + public static final String BK_FAILED_GET_NETWORK_CARD = "bkFailedGetNetworkCard";// 获取网卡失败 + public static final String BK_MANUAL_TRIGGER = "bkManualTrigger";// 手动触发 + public static final String BK_BUILD_TRIGGER = "bkBuildTrigger";// 构建触发 + public static final String BK_VIEW_DETAILS = "bkSeeDetails";// 查看详情 + public static final String BK_PROJECT_ID = "bkProjectId";// # 项目ID: + public static final String BK_PIPELINE_NAME = "bkPipelineName";// # 流水线名称: + public static final String BK_CREATE_SERVICE = "bkCreateService";// 创建{0}服务 + public static final String BK_SESSION_ID = "bkSessionId";// 会话ID + public static final String BK_GROUP_ID = "bkGroupId";// 群ID + public static final String BK_THIS_GROUP_ID = "bkThisGroupId";// 本群ID={0}。PS:群ID可用于蓝盾平台上任意企业微信群通知。 + public static final String BK_MISSING_RESOURCE_DEPENDENCY = "bkMissingResourceDependency";// 依赖的资源不存在 + + public static final String BK_REQUEST_TIMED_OUT = "bkRequestTimedOut";// 请求超时 + public static final String BK_QUERY_PARAM_REQUEST_ERROR = "bkQueryParamRequestError";// 查询参数请求错误 + public static final String BK_JSON_BAD_PARAMETERS = "bkJsonBadParameters";// JSON参数错误/Bad Parameters in json + // 请求体内容参数错误。温馨提示:请确认{0}是否符合要求 + public static final String BK_REQUEST_BODY_CONTENT_PARAMETER_INCORRECT = "bkRequestBodyContentParameterIncorrect"; + public static final String BK_REQUESTED_RESOURCE_DOES_NOT_EXIST = "bkRequestedResourceDoesNotExist";// 请求的资源不存在 + public static final String BK_NOT_OAUTH_CERTIFICATION = "bkNotOauthCertification";// 你没有Oauth认证 + public static final String BK_QUERY_PARAM_REQUEST_EMPTY = "bkQueryParamRequestEmpty";// 请求的参数内容为空 + public static final String BK_QUERY_PARAM_TYPE_ERROR = "bkQueryParamTypeError";// 查询参数类型错误 + // 你没有权限进行该操作 + public static final String BK_NOT_HAVE_PERMISSION_PERFORM_THIS_OPERATION = "bkNotHavePermissionPerformThisOperation"; + // 访问后台数据失败,已通知产品、开发,请稍后重试 + public static final String BK_FAILED_ACCESS_BACKGROUND_DATA = "bkFailedAccessBackgroundData"; + // 未授权访问的资源 + public static final String BK_RESOURCES_THAT_NOT_AUTHORIZED_ACCESS = "bkResourcesThatNotAuthorizedAccess"; + public static final String BK_CODE_BASE_TRIGGERING = "bkCodeBaseTriggering";// 代码库触发 + public static final String BK_FAILED_START_BUILD_MACHINE = "bkFailedStartBuildMachine";// 启动构建机失败 + + public static final String CREATE_BRANCH = "bkCreateBranch";// 创建分支 + public static final String DELETE_BRANCH = "bkDeleteBranch";// 删除分支 + + public static final String GET_PROJECT_INFO = "bkGetProjectInfo";// 获取项目详情 + + public static final String OPERATION_BRANCH = "bkOperationBranch";// 拉分支 + public static final String OPERATION_TAG = "bkOperationTag";// 拉标签 + public static final String OPERATION_ADD_WEBHOOK = "bkOperationAddWebhook";// 添加WEBHOOK + public static final String OPERATION_UPDATE_WEBHOOK = "bkOperationUpdateWebhook";// 修改WEBHOOK + public static final String OPERATION_LIST_WEBHOOK = "bkOperationListWebhook";// 查询WEBHOOK + public static final String OPERATION_ADD_COMMIT_CHECK = "bkOperationAddCommitCheck";// 添加COMMIT CHECK + public static final String OPERATION_ADD_MR_COMMENT = "bkOperationAddMrComment";// 添加MR COMMENT + public static final String OPERATION_COMMIT = "bkOperationCommit";// 拉提交记录 + public static final String OPERATION_COMMIT_DIFF = "bkOperationCommitDiff";// 查询commit变化 + public static final String OPERATION_UNLOCK_HOOK_LOCK = "bkOperationUnlockHookLock";// 解锁hook锁 + public static final String OPERATION_MR_CHANGE = "bkOperationMrChange";// 查询合并请求的代码变更 + public static final String OPERATION_MR_INFO = "bkOperationMrInfo";// 查询项目合并请求 + public static final String OPERATION_GET_CHANGE_FILE_LIST = "bkOperationGetChangeFileList";// 查询变更文件列表 + public static final String OPERATION_GET_MR_COMMIT_LIST = "bkOperationGetMrCommitList";// 获取合并请求中的提交 + public static final String OPERATION_PROJECT_USER_INFO = "bkOperationProjectUserInfo";// 获取项目中成员信息 + public static final String OPERATION_TAPD_WORKITEMS = "bkOperationTapdWorkItems";// 查看绑定的TAPD单 + public static final String BK_USER_GROUP_CRATE_TIME = "bkUserGroupCrateTime";// {0} 用户组:{1},由{2} 创建于 + public static final String BK_USER_RATING_ADMIN_CRATE_TIME = "bkUserRatingAdminCrateTime";// {0} 分级管理员,由{1} 创建于 + public static final String BK_SECOND_LEVEL_ADMIN_CREATE = "bkSecondLevelAdminCreate";// {0} 二级管理员, 由{1} 创建于 + public static final String BK_SECOND_LEVEL_ADMIN_REVISE = "bkSecondLevelAdminRevise";// {0} 二级管理员, 由{1} 修改于 + // 用户 {0} 申请{1}蓝盾项目 {2} ,请审批! + public static final String BK_USER_REQUESTS_THE_PROJECT = "bkUserRequestsTheProject"; + public static final String BK_ENV_NOT_YET_SUPPORTED = "bkEnvNotYetSupported";// 尚未支持 {0} {1},请联系 管理员 添加对应版本 + + public static final String BK_BUILD_ENV_TYPE = "BUILD_ENV_TYPE_";// 构建环境- + public static final String BK_BUILD_ENV_TYPE_BUILDLESS = "BUILD_ENV_TYPE_BUILDLESS";// 无编译环境 + public static final String BK_BUILD_ENV_TYPE_BUILD_TRIGGERS = "BUILD_ENV_TYPE_BUILD_TRIGGER";// 构建触发 +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/LeafAllocConstant.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/LeafAllocConstant.java new file mode 100644 index 0000000..9412c12 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/LeafAllocConstant.java @@ -0,0 +1,64 @@ +package cd.casic.pipeline.commons.constant; + +/** + * @Classname LeafAllocConstant + * @Description 流水线的枚举 + * @Date 2025/3/18 10:16 + * @author mianbin + */ +public class LeafAllocConstant { + /** =========================================流水线====================================================== */ + public static final String AUDIT_RESOURCE = "AUDIT_RESOURCE"; + + public static final String PIPELINE_RESOURCE = "PIPELINE_RESOURCE"; + + public static final String PIPELINE_VERSION_SIMPLE_RESOURCE = "PIPELINE_VERSION_SIMPLE_RESOURCE"; + + public static final String PIPELINE_SETTING_RESOURCE = "PIPELINE_SETTING_RESOURCE"; + + public static final String PIPELINE_VERSION_SETTING_RESOURCE = "PIPELINE_VERSION_SETTING_RESOURCE"; + + public static final String PIPELINE_LABEL_PIPELINE_RESOURCE = "PIPELINE_LABEL_PIPELINE_RESOURCE"; + + public static final String TEMPLATE_PIPELINE_RESOURCE = "TEMPLATE_PIPELINE_RESOURCE"; + + public static final String PIPELINE_BUILD_SUMMARY = "PIPELINE_BUILD_SUMMARY"; + + public static final String PIPELINE_BUILD_HISTORY = "PIPELINE_BUILD_HISTORY"; + + public static final String PIPELINE_BUILD_TASK = "PIPELINE_BUILD_TASK"; + + public static final String PIPELINE_BUILD_CONTAINER = "PIPELINE_BUILD_CONTAINER"; + + public static final String PIPELINE_BUILD_STAGE = "PIPELINE_BUILD_STAGE"; + + public static final String PIPELINE_BUILD_RECORD_CONTAINER = "PIPELINE_BUILD_RECORD_CONTAINER"; + + public static final String PIPELINE_BUILD_RECORD_MODEL = "PIPELINE_BUILD_RECORD_MODEL"; + + public static final String PIPELINE_BUILD_RECORD_STAGE = "PIPELINE_BUILD_RECORD_STAGE"; + + public static final String PIPELINE_BUILD_RECORD_TASK = "PIPELINE_BUILD_RECORD_TASK"; + + public static final String PIPELINE_BUILD_DETAIL = "PIPELINE_BUILD_DETAIL"; + + public static final String PIPELINE_LABEL_PIPELINE = "PIPELINE_LABEL_PIPELINE"; + + public static final String STAGE_TAG = "STAGE_TAG"; + + public static final String PIPELINE_JOB_MUTEX_GROUP_RESOURCE = "PIPELINE_JOB_MUTEX_GROUP_RESOURCE"; + + public static final String MODEL_TASK = "PIPELINE_MODEL_TASK"; + + public static final String PIPELINE_TRIGGER_REVIEW = "PIPELINE_TRIGGER_REVIEW"; + + public static final String PIPELINE_BUILD_VAR = "PIPELINE_BUILD_VAR"; + + /** =========================================项目====================================================== */ + public static final String PROJECT_RESOURCE = "PROJECT_RESOURCE"; + + /** ========================================日志===================================================== */ + public static final String LOG_STATUS = "LOG_STATUS"; + public static final String LOG_SUBTAGS = "LOG_SUBTAGS"; + public static final String LOG_INDICES_V2 = "LOG_INDICES_V2"; +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/OpsHeader.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/OpsHeader.java new file mode 100644 index 0000000..f133887 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/constant/OpsHeader.java @@ -0,0 +1,70 @@ +package cd.casic.pipeline.commons.constant; + +import lombok.NoArgsConstructor; + +/** + * @author by mianbin + * @Classname OpsHeader + * @Description 重要,莫动 + * @Date 2025/3/19 14:49 + */ +@NoArgsConstructor +public final class OpsHeader { + + public static final String AUTH_HEADER_USER_ID = "X-DEVOPS-UID"; + public static final String AUTH_HEADER_USER_ID_DEFAULT_VALUE = "admin"; + public static final String AUTH_HEADER_BUILD_ID = "X-DEVOPS-BUILD-ID"; + public static final String AUTH_HEADER_VM_SEQ_ID = "X-DEVOPS-VM-SID"; + public static final String AUTH_HEADER_VM_NAME = "X-DEVOPS-VM-NAME"; + public static final String AUTH_HEADER_PROJECT_ID = "X-DEVOPS-PROJECT-ID"; + public static final String AUTH_HEADER_AGENT_SECRET_KEY = "X-DEVOPS-AGENT-SECRET-KEY"; + public static final String AUTH_HEADER_AGENT_ID = "X-DEVOPS-AGENT-ID"; + public static final String AUTH_HEADER_PIPELINE_ID = "X-DEVOPS-PIPELINE-ID"; + public static final String AUTH_HEADER_REGION = "X-DEVOPS-REGION"; + public static final String AUTH_HEADER_DEVOPS_APP_CODE = "X-DEVOPS-APP-CODE"; + public static final String AUTH_HEADER_DEVOPS_APP_SECRET = "X-DEVOPS-APP-SECRET"; + public static final String AUTH_HEADER_DEVOPS_BUILD_TYPE = "X-DEVOPS-BUILD-TYPE"; + public static final String AUTH_HEADER_DEVOPS_USER_ID = AUTH_HEADER_USER_ID; + public static final String AUTH_HEADER_DEVOPS_USER_ID_DEFAULT_StringUE = "admin"; + public static final String AUTH_HEADER_DEVOPS_APP_CODE_DEFAULT_StringUE = "opsci"; + public static final String AUTH_HEADER_DEVOPS_BG_ID = "X-DEVOPS-BG-ID"; + public static final String AUTH_HEADER_DEVOPS_DEPT_ID = "X-DEVOPS-DEPT-ID"; + public static final String AUTH_HEADER_DEVOPS_CENTER_ID = "X-DEVOPS-CENTER-ID"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_TYPE = "X-DEVOPS-ORGANIZATION-TYPE"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_TYPE_BG = "BG"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_TYPE_DEPARTMENT = "DEPARTMENT"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_TYPE_CENTER = "CENTER"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_ID = "X-DEVOPS-ORGANIZATION-ID"; + public static final String AUTH_HEADER_DEVOPS_ORGANIZATION_NAME = "X-DEVOPS-ORGANIZATION-NAME"; + public static final String AUTH_HEADER_DEVOPS_PROJECT_ID = "X-DEVOPS-PROJECT-ID"; + public static final String AUTH_HEADER_DEVOPS_PIPELINE_ID = "X-DEVOPS-PIPELINE-ID"; + public static final String AUTH_HEADER_DEVOPS_BUILD_ID = "X-DEVOPS-BUILD-ID"; + public static final String AUTH_HEADER_DEVOPS_VM_SEQ_ID = "X-DEVOPS-VM-SID"; + public static final String AUTH_HEADER_DEVOPS_VM_NAME = "X-DEVOPS-VM-NAME"; + public static final String AUTH_HEADER_DEVOPS_REAL_IP = "X-DEVOPS-REAL-IP"; + public static final String AUTH_HEADER_DEVOPS_AGENT_ID = "X-DEVOPS-AGENT-ID"; + public static final String AUTH_HEADER_DEVOPS_AGENT_SECRET_KEY = "X-DEVOPS-AGENT-SECRET-KEY"; + public static final String AUTH_HEADER_DEVOPS_BK_TOKEN = "X-DEVOPS-BK-TOKEN"; + public static final String AUTH_HEADER_DEVOPS_ACCESS_TOKEN = "X-DEVOPS-ACCESS-TOKEN"; + public static final String AUTH_HEADER_DEVOPS_BK_TICKET = "X-DEVOPS-BK-TOKEN"; + public static final String AUTH_HEADER_DEVOPS_USER_CHINESE_NAME = "X-DEVOPS-CHINESE-NAME"; + public static final String AUTH_HEADER_DEVOPS_USER_PAAS_ID = "X-DEVOPS-PAAS-USER-ID"; + public static final String AUTH_HEADER_DEVOPS_ORIGINAL_HOST = "X-DEVOPS-ORIGINAL-HOST"; + public static final String AUTH_HEADER_DEVOPS_JWT_TOKEN = "X-DEVOPS-JWT-TOKEN"; + public static final String AUTH_HEADER_IAM_TOKEN = "Authorization"; + public static final String AUTH_HEADER_DEVOPS_SIGN_INFO = "X-DEVOPS-SIGN-INFO"; + public static final String AUTH_HEADER_PLATFORM = "X-DEVOPS-PLATFORM"; + public static final String AUTH_HEADER_APP_VERSION = "X-DEVOPS-APP-VERSION"; + public static final String AUTH_HEADER_GATEWAY_TAG = "X-GATEWAY-TAG"; + public static final String AUTH_HEADER_DEVOPS_CI_TASK_ID = "X-DEVOPS-CI-TASK-ID"; + public static final String SIGN_HEADER_TIMESTAMP = "X-DEVOPS-TIMESTAMP"; + public static final String SIGN_HEADER_NONCE = "X-DEVOPS-NONCE"; + public static final String SING_HEADER_SIGNATURE = "X-DEVOPS-SIGNATURE"; + public static final String AUTH_HEADER_GITHUB_TOKEN = "X-GITHUB-TOKEN"; + public static final String AUTH_HEADER_GIT_TYPE = "X-DEVOPS-STREAM-GIT-TYPE"; + public static final String AUTH_HEADER_BK_CI_LOGIN_TOKEN = "X-DEVOPS-CI-LOGIN-TOKEN"; + public static final String AUTH_HEADER_DEVOPS_SERVICE_NAME = "X-DEVOPS-SERVICE-NAME"; + public static final String AUTH_HEADER_CODECC_OPENAPI_TOKEN = "X-CODECC-OPENAPI-TOKEN"; + + +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/BkStyleEnum.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/BkStyleEnum.java new file mode 100644 index 0000000..8db88cb --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/BkStyleEnum.java @@ -0,0 +1,38 @@ +package cd.casic.pipeline.commons.enums; + +/** + * @Classname StyleEnum + * @Description ops类型枚举 + * @Date 2025/3/18 10:26 + * @author mianbin + */ +public enum BkStyleEnum { + COMMON_STYLE("^(.|\\r|\\n)*$"), + NUMBER_STYLE("[0-9]*$"), + CODE_STYLE("^[a-zA-Z_][\\w-()]{0,31}$"), + ID_STYLE("^[\\w-]{1,64}$"), + NAME_STYLE("^[\\w-\\u4E00-\\u9FBB\\u3400-\\u4DBF\\uF900-\\uFAD9\\u3000-\\u303F\\u2000-\\u206F\\uFF00-\\uFFEF.()\\s]{1,40}$"), + STORE_MEMBER_TYPE_STYLE("^ADMIN|DEVELOPER$"), + EMAIL_STYLE("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"), + AUTH_STYLE("^HTTP|HTTPS|OAUTH|SSH$"), + NOTE_STYLE("^[A-Za-z0-9\\u4E00-\\u9FBB\\u3400-\\u4DBF\\uF900-\\uFAD9\\u3000-\\u303F" + + "\\u2000-\\u206F\\uFF00-\\uFFEF.。??!!,(),、;;::'‘’“”\"…\\s]{1,256}$"), + VISIBILITY_LEVEL_STYLE("^PRIVATE|LOGIN_PUBLIC$"), + LANGUAGE_STYLE("^java|python|nodejs|kotilin|golang|c|c++|php|c#$"), + BOOLEAN_STYLE("^true|false$"), + SCOPE_STYLE("^TEST|PRD|ALL$"), + SERVICE_CODE_STYLE("^[a-z][([-a-z-0-9]*[a-z-0-9])?]{0,31}$"), + BUILD_NUM_RULE_STYLE("^[\\w-{}() +?.:$\"]{1,256}$"), + STORE_FIELD_TYPE_STYLE("^BACKEND|FRONTEND|ALL$"), + PAGE_SIZE_STYLE("^100$|^([1-9]|[1-9]\\d)$"); + + private final String style; + + BkStyleEnum(String style) { + this.style = style; + } + + public String getStyle() { + return style; + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/CommonStatusEnum.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/CommonStatusEnum.java new file mode 100644 index 0000000..8b2255a --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/CommonStatusEnum.java @@ -0,0 +1,38 @@ +package cd.casic.pipeline.commons.enums; + +import cd.casic.framework.commons.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * @Classname CommonStatusEnum + * @Description + * @Date 2025/3/18 11:26 + * @author mianbin + */ +@Getter +@AllArgsConstructor +public enum CommonStatusEnum implements IntArrayValuable { + + ENABLE(0, "开启"), + DISABLE(1, "关闭"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CommonStatusEnum::getStatus).toArray(); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/DateIntervalEnum.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/DateIntervalEnum.java new file mode 100644 index 0000000..9400c61 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/DateIntervalEnum.java @@ -0,0 +1,46 @@ +package cd.casic.pipeline.commons.enums; + +import cd.casic.framework.commons.core.IntArrayValuable; +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import java.util.Arrays; + +/** + * @Classname DateIntervalEnum + * @Description 时间间隔的枚举 + * @Date 2025/3/18 11:26 + * @author mianbin + */ +@Getter +@AllArgsConstructor +public enum DateIntervalEnum implements IntArrayValuable { + + DAY(1, "天"), + WEEK(2, "周"), + MONTH(3, "月"), + QUARTER(4, "季度"), + YEAR(5, "年") + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getInterval).toArray(); + + /** + * 类型 + */ + private final Integer interval; + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + + public static DateIntervalEnum valueOf(Integer interval) { + return ArrayUtil.firstMatch(item -> item.getInterval().equals(interval), DateIntervalEnum.values()); + } + +} \ No newline at end of file diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SubjectScopeType.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SubjectScopeType.java new file mode 100644 index 0000000..8dd9a00 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SubjectScopeType.java @@ -0,0 +1,27 @@ +package cd.casic.pipeline.commons.enums; + + +/** + * @Classname SubjectScopeType + * @Description 最大授权范围类型,这里先这样,后面要扩展 + * @Date 2025/3/18 11:26 + * @author mianbin + */ +public enum SubjectScopeType { + //院、所、中心 + ORGANIZATION("organization"), + // 部门、事业部、产线 + DEPARTMENT("depart"), + // 用户 + USER("user"); + + private final String value; + + SubjectScopeType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SystemModuleEnum.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SystemModuleEnum.java new file mode 100644 index 0000000..ad8c108 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/SystemModuleEnum.java @@ -0,0 +1,62 @@ +package cd.casic.pipeline.commons.enums; + +/** + * @author mianbin + * @Classname SystemModuleEnum + * @Description 最大授权范围类型,这里先这样,后面要扩展 + * @Date 2025/3/18 11:26 + */ +public enum SystemModuleEnum { + COMMON("00"), // 公共模块 + PROCESS("01"), // 流水线 + ARTIFACTORY("02"), // 版本仓库 + DISPATCH("03"), // 公共模块 + DOCKERHOST("04"), // DOCKER机器 + ENVIRONMENT("05"), // 环境 + EXPERIENCE("06"), // 版本体验 + IMAGE("07"), // 镜像 + LOG("08"), // 日志 + MEASURE("09"), // 度量 + MONITORING("10"), // 监控 + NOTIFY("11"), // 通知 + OPENAPI("12"), // 开放平台API + PLUGIN("13"), // 插件 + QUALITY("14"), // 质量红线 + REPOSITORY("15"), // 代码库 + SCM("16"), // 软件配置管理 + SUPPORT("17"), // 支撑服务 + TICKET("18"), // 证书凭据 + PROJECT("19"), // 项目管理 + STORE("20"), // 商店 + AUTH("21"), // 权限 + SIGN("22"), // 签名服务 + METRICS("23"), // 度量服务 + EXTERNAL("24"), // 外部扩展 + PREBUILD("25"), // 预构建 + DISPATCH_KUBERNETES("26"), // k8s分发服务 + BUILDLESS("27"), // buildless服务 + LAMBDA("28"), // lambda服务 + STREAM("29"), // stream服务 + WORKER("30"), // 度量服务 + DISPATCH_DOCKER("31"), // docker分发服务 + REMOTEDEV("32"); // 远程开发服务 + + private final String code; + + SystemModuleEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static String getSystemModule(String code) { + for (SystemModuleEnum value : values()) { + if (value.getCode().equals(code)) { + return value.name(); + } + } + return COMMON.name(); + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/UserTypeEnum.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/UserTypeEnum.java new file mode 100644 index 0000000..8a4229e --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/enums/UserTypeEnum.java @@ -0,0 +1,41 @@ +package cd.casic.pipeline.commons.enums; + +import cd.casic.framework.commons.core.IntArrayValuable; +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import java.util.Arrays; + +/** + * @Classname UserTypeEnum + * @Description 全局用户类型枚举 + * @Date 2025/3/18 10:16 + * @author mianbin + */ +@AllArgsConstructor +@Getter +public enum UserTypeEnum implements IntArrayValuable { + + MEMBER(1, "普通用户"), + ADMIN(2, "管理员"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(UserTypeEnum::getValue).toArray(); + + /** + * 类型 + */ + private final Integer value; + /** + * 类型名 + */ + private final String name; + + public static UserTypeEnum valueOf(Integer value) { + return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values()); + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/functions/Preconditions.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/functions/Preconditions.java new file mode 100644 index 0000000..e988e35 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/functions/Preconditions.java @@ -0,0 +1,23 @@ +package cd.casic.pipeline.commons.functions; + +import lombok.SneakyThrows; + +/** + * 前置条件校验工具类 + */ +public class Preconditions { + + + public static void checkNotNull(Object obj, Exception exception) throws Exception { + if (obj == null){ + throw exception; + } + } + + @SneakyThrows + public static void checkTrue(Boolean condition, Exception exception){ + if (!condition){ + throw exception; + } + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocMapper.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocMapper.java new file mode 100644 index 0000000..d1e6fed --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocMapper.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.commons.operationid; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.commons.operationid.entity.LeafAlloc; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author by mianbin + * @Classname LeafAllocMapper + * @Description TODO + * @Date 2025/3/19 10:41 + */ +@Mapper +public interface LeafAllocMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocService.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocService.java new file mode 100644 index 0000000..997be6a --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocService.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.commons.operationid; + + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.commons.operationid.entity.LeafAlloc; + +import java.util.List; +/** + * @author by mianbin + * @Classname LeafAllocService + * @Description TODO + * @Date 2025/3/19 10:41 + */ +public interface LeafAllocService { + + List getAllLeafAllocs(); + + LeafAlloc updateMaxIdAndGetLeafAlloc(String key); + + LeafAlloc updateMaxIdByCustomStepAndGetLeafAlloc(LeafAlloc leafAlloc); + + List getAllKeys(); + + boolean create(LeafAlloc leafAlloc); + + boolean update(LeafAlloc leafAlloc); + + boolean batchCreate(List leafAllocs); +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocServiceImpl.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocServiceImpl.java new file mode 100644 index 0000000..8b4a378 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/LeafAllocServiceImpl.java @@ -0,0 +1,82 @@ +package cd.casic.pipeline.commons.operationid; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import cd.casic.framework.commons.util.date.DateUtils; +import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX; +import cd.casic.pipeline.commons.operationid.entity.LeafAlloc; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author by mianbin + * @Classname LeafAllocServiceImpl + * @Description TODO + * @Date 2025/3/19 10:41 + */ +@Slf4j +@Service +public class LeafAllocServiceImpl implements LeafAllocService { + + @Resource + private LeafAllocMapper leafAllocMapper; + + @Override + public List getAllLeafAllocs() { + List leafAllocs = leafAllocMapper.selectList(); + return CollUtil.emptyIfNull(leafAllocs); + } + + @Override + public LeafAlloc updateMaxIdAndGetLeafAlloc(String key) { + LeafAlloc leafAlloc = leafAllocMapper.selectOne(LeafAlloc::getKey, key); + leafAlloc.setMaxId(leafAlloc.getMaxId() + leafAlloc.getStep()); + return leafAllocMapper.updateById(leafAlloc) > 0 ? leafAlloc : null; + } + + @Override + public LeafAlloc updateMaxIdByCustomStepAndGetLeafAlloc(LeafAlloc condition) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(LeafAlloc::getKey, condition.getKey()); + condition.setMaxId(condition.getMaxId() + condition.getStep()); + return leafAllocMapper.updateById(condition) > 0 ? condition : null; + } + + @Override + public List getAllKeys() { + return leafAllocMapper.selectList().stream().map(LeafAlloc::getKey).collect(Collectors.toList()); + } + + @Override + public boolean create(LeafAlloc leafAlloc) { + LeafAlloc one = leafAllocMapper.selectOne(LeafAlloc::getKey, leafAlloc.getKey()); + if (one != null) { + throw new ServiceException(GlobalErrorCodeConstants.ID_DUPLICATION); + } + return leafAllocMapper.insert(leafAlloc) > 0 ? true : false; + } + + @Override + public boolean update(LeafAlloc leafAlloc) { + LeafAlloc one = leafAllocMapper.selectOne(LeafAlloc::getKey, leafAlloc.getKey(), LeafAlloc::getId, leafAlloc.getId()); + if (one != null) { + throw new ServiceException(GlobalErrorCodeConstants.ID_DUPLICATION); + } + one.setUpdateTime(DateUtil.toLocalDateTime(new Date())); + return leafAllocMapper.updateById(one) > 0 ? true : false; + } + + @Override + public boolean batchCreate(List leafAllocs) { + return leafAllocMapper.insertBatch(leafAllocs); + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/SegmentIdGeneratorImpl.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/SegmentIdGeneratorImpl.java new file mode 100644 index 0000000..430bc32 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/SegmentIdGeneratorImpl.java @@ -0,0 +1,304 @@ +package cd.casic.pipeline.commons.operationid; + + +import cd.casic.framework.commons.exception.ErrorCode; +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import cd.casic.framework.commons.util.generator.IdGenerator; +import cd.casic.pipeline.commons.constant.LeafAllocConstant; +import cd.casic.pipeline.commons.operationid.entity.LeafAlloc; +import cd.casic.pipeline.commons.operationid.entity.Segment; +import cd.casic.pipeline.commons.operationid.entity.SegmentBuffer; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author by mianbin + * @Classname SegmentIdGeneratorImpl + * @Description TODO + * @Date 2025/3/19 10:41 + */ +@Slf4j +public class SegmentIdGeneratorImpl implements IdGenerator { + + /** + * IDCache未初始化成功时的异常码 + */ + private static final long EXCEPTION_ID_IDCACHE_INIT_FALSE = -1; + /** + * key不存在时的异常码 + */ + private static final long EXCEPTION_ID_KEY_NOT_EXISTS = -2; + /** + * SegmentBuffer中的两个Segment均未从DB中装载时的异常码 + */ + private static final long EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL = -3; + /** + * 最大步长不超过100,0000 + */ + private static final int MAX_STEP = 1000000; + /** + * 一个Segment维持时间为15分钟 + */ + private static final long SEGMENT_DURATION = 15 * 60 * 1000L; + private volatile boolean initOK = false; + private final Map cache = new ConcurrentHashMap<>(); + + private LeafAllocService leafAllocService; + + private ThreadPoolExecutor threadPoolExecutor; + + private ScheduledExecutorService scheduledExecutorService; + + public SegmentIdGeneratorImpl(LeafAllocService leafAllocService, ThreadPoolExecutor threadPoolExecutor, + ScheduledExecutorService scheduledExecutorService) { + this.leafAllocService = leafAllocService; + this.threadPoolExecutor = threadPoolExecutor; + this.scheduledExecutorService = scheduledExecutorService; + } + + @Override + public boolean init() { + log.info("Init ..."); + // 确保加载到kv后才初始化成功 + updateCacheFromDb(); + initSave(); + initOK = true; + updateCacheFromDbAtEveryMinute(); + return initOK; + } + + private void initSave() { + try { + Class clazz = LeafAllocConstant.class; + Field[] fields = clazz.getFields(); + List notExist = new ArrayList<>(); + for (Field field : fields) { + String str = (String) field.get(null); + if (!cache.containsKey(str)) { + LeafAlloc leafAlloc = new LeafAlloc(); + leafAlloc.setKey(str); + leafAlloc.setMaxId(1L); + leafAlloc.setStep(50); + notExist.add(leafAlloc); + } + } + + if (!notExist.isEmpty()) { + leafAllocService.batchCreate(notExist); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + log.error(e.getMessage()); + } + } + + @Override + public List batchGenerateSegmentId(String key, Integer num) { + + List res = new ArrayList<>(); + while (num-- > 0) { + res.add(get(key)); + } + + return res; + } + + private void updateCacheFromDbAtEveryMinute() { + + scheduledExecutorService.scheduleWithFixedDelay(this::updateCacheFromDb, 60, 60, TimeUnit.SECONDS); + } + + private void updateCacheFromDb() { + log.info("update cache from db"); + try { + List dbTags = leafAllocService.getAllKeys(); + if (dbTags == null || dbTags.isEmpty()) { + return; + } + List cacheTags = new ArrayList<>(cache.keySet()); + Set insertTagsSet = new HashSet<>(dbTags); + Set removeTagsSet = new HashSet<>(cacheTags); + //db中新加的tags灌进cache + for (String tmp : cacheTags) { + insertTagsSet.remove(tmp); + } + for (String tag : insertTagsSet) { + SegmentBuffer buffer = new SegmentBuffer(); + buffer.setKey(tag); + Segment segment = buffer.getCurrent(); + segment.setValue(new AtomicLong(0)); + segment.setMax(0); + segment.setStep(0); + cache.put(tag, buffer); + log.info("Add tag {} from db to IdCache, SegmentBuffer {}", tag, buffer); + } + //cache中已失效的tags从cache删除 + for (String tmp : dbTags) { + removeTagsSet.remove(tmp); + } + for (String tag : removeTagsSet) { + cache.remove(tag); + log.info("Remove tag {} from IdCache", tag); + } + } catch (Exception e) { + log.warn("update cache from db exception", e); + } + } + + @Override + public Long get(final String key) { + if (!initOK) { + throw new ServiceException(ErrorCode.builder().msg("IDCache未初始化成功").code(0).build()); + } + if (cache.containsKey(key)) { + SegmentBuffer buffer = cache.get(key); + if (!buffer.isInitOk()) { + synchronized (buffer) { + if (!buffer.isInitOk()) { + try { + updateSegmentFromDb(key, buffer.getCurrent()); + log.info("Init buffer. Update leafkey {} {} from db", key, buffer.getCurrent()); + buffer.setInitOk(true); + } catch (Exception e) { + log.warn("Init buffer {} exception", buffer.getCurrent(), e); + } + } + } + } + return getIdFromSegmentBuffer(cache.get(key)); + } + log.warn("key({})不存在", key); + throw new ServiceException(ErrorCode.builder().msg(String.format("key(%s)不存在", key)).code(0).build()); + } + + public void updateSegmentFromDb(String key, Segment segment) { + SegmentBuffer buffer = segment.getBuffer(); + LeafAlloc leafAlloc; + if (!buffer.isInitOk()) { + leafAlloc = leafAllocService.updateMaxIdAndGetLeafAlloc(key); + buffer.setStep(leafAlloc.getStep()); + //leafAlloc中的step为DB中的step + buffer.setMinStep(leafAlloc.getStep()); + } else if (buffer.getUpdateTimestamp() == 0) { + leafAlloc = leafAllocService.updateMaxIdAndGetLeafAlloc(key); + buffer.setUpdateTimestamp(System.currentTimeMillis()); + buffer.setStep(leafAlloc.getStep()); + //leafAlloc中的step为DB中的step + buffer.setMinStep(leafAlloc.getStep()); + } else { + long duration = System.currentTimeMillis() - buffer.getUpdateTimestamp(); + int nextStep = buffer.getStep(); + if (duration < SEGMENT_DURATION) { + if (nextStep * 2 > MAX_STEP) { + //do nothing + } else { + nextStep = nextStep * 2; + } + } else if (duration < SEGMENT_DURATION * 2) { + //do nothing with nextStep + } else { + nextStep = nextStep / 2 >= buffer.getMinStep() ? nextStep / 2 : nextStep; + } + log.info("leafKey[{}], step[{}], duration[{}mins], nextStep[{}]", key, buffer.getStep(), String.format("%.2f", ((double) duration / (1000 * 60))), nextStep); + LeafAlloc temp = new LeafAlloc(); + temp.setKey(key); + temp.setStep(nextStep); + leafAlloc = leafAllocService.updateMaxIdByCustomStepAndGetLeafAlloc(temp); + buffer.setUpdateTimestamp(System.currentTimeMillis()); + buffer.setStep(nextStep); + //leafAlloc的step为DB中的step + buffer.setMinStep(leafAlloc.getStep()); + } + // must set value before set max + long value = leafAlloc.getMaxId() - buffer.getStep(); + segment.getValue().set(value); + segment.setMax(leafAlloc.getMaxId()); + segment.setStep(buffer.getStep()); + } + + public Long getIdFromSegmentBuffer(final SegmentBuffer buffer) { + while (true) { + buffer.rLock().lock(); + try { + final Segment segment = buffer.getCurrent(); + if (!buffer.isNextReady() && (segment.getIdle() < 0.9 * segment.getStep()) && buffer.getThreadRunning().compareAndSet(false, true)) { + threadPoolExecutor.execute(() -> { + Segment next = buffer.getSegments()[buffer.nextPos()]; + boolean updateOk = false; + try { + updateSegmentFromDb(buffer.getKey(), next); + updateOk = true; + log.info("update segment {} from db {}", buffer.getKey(), next); + } catch (Exception e) { + log.warn(buffer.getKey() + " updateSegmentFromDb exception", e); + } finally { + if (updateOk) { + buffer.wLock().lock(); + buffer.setNextReady(true); + buffer.getThreadRunning().set(false); + buffer.wLock().unlock(); + } else { + buffer.getThreadRunning().set(false); + } + } + }); + } + long value = segment.getValue().getAndIncrement(); + if (value < segment.getMax()) { + return value; + } + } finally { + buffer.rLock().unlock(); + } + waitAndSleep(buffer); + buffer.wLock().lock(); + try { + final Segment segment = buffer.getCurrent(); + long value = segment.getValue().getAndIncrement(); + if (value < segment.getMax()) { + return value; + } + if (buffer.isNextReady()) { + buffer.switchPos(); + buffer.setNextReady(false); + } else { + log.error("Both two segments in {} are not ready! ,请稍后再试", buffer); + } + } finally { + buffer.wLock().unlock(); + } + } + } + + private void waitAndSleep(SegmentBuffer buffer) { + int roll = 0; + while (buffer.getThreadRunning().get()) { + roll += 1; + if (roll > 10000) { + try { + TimeUnit.MILLISECONDS.sleep(10); + break; + } catch (InterruptedException e) { + log.warn("Thread {} Interrupted", Thread.currentThread().getName()); + break; + } + } + } + } + + public List getAllLeafAllocs() { + return leafAllocService.getAllLeafAllocs(); + } + + public Map getCache() { + return cache; + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/LeafAlloc.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/LeafAlloc.java new file mode 100644 index 0000000..5e4c9ad --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/LeafAlloc.java @@ -0,0 +1,60 @@ +package cd.casic.pipeline.commons.operationid.entity; + +import cd.casic.framework.commons.util.validation.ValidGroup; +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * @author mianbin + * @Classname LeafAlloc + * @Description 业务id实体 + * @Date 2025/3/18 14:16 + */ +@Data +@Accessors(chain = true) +@Schema(description = "生成唯一id的实体") +public class LeafAlloc extends BaseDO { + private static final long serialVersionUID = 1L; + + @Schema(description = "主键") + @Null(message = "新增id需为空", groups = ValidGroup.Create.class) + @NotNull(message = "修改id不能为空", groups = ValidGroup.Update.class) + private String id; + + /** + * 业务key + */ + @Schema(description = "业务key", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "key不能为空") + private String key; + + /** + * 当前已分配的最大id + */ + @Schema(description = "当前已分配的最大id(新增建议从1开始)", requiredMode = Schema.RequiredMode.REQUIRED, defaultValue = "1") + @NotNull(message = "maxId不能为空") + @Size(min = 1, message = "最小为1") + private Long maxId; + + /** + * 初始步长,也是动态调整的最小步长 + */ + @Schema(description = "初始步长,也是动态调整的最小步长(从数据库一次获取的id数量)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "step不能为空") + @Size(min = 1, message = "最小为1") + private Integer step; + + /** + * 业务key描述 + */ + @Schema(description = "业务key描述", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String description; + + +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Segment.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Segment.java new file mode 100644 index 0000000..26d89b3 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Segment.java @@ -0,0 +1,28 @@ +package cd.casic.pipeline.commons.operationid.entity; + +import lombok.Data; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author mianbin + * @Classname Segment + * @Description + * @Date 2025/3/18 14:16 + */ +@Data +public class Segment { + private AtomicLong value = new AtomicLong(0); + private volatile long max; + private volatile int step; + private final SegmentBuffer buffer; + + public Segment(SegmentBuffer buffer) { + this.buffer = buffer; + } + + public long getIdle() { + return this.getMax() - getValue().get(); + } + +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/SegmentBuffer.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/SegmentBuffer.java new file mode 100644 index 0000000..6d7ad70 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/SegmentBuffer.java @@ -0,0 +1,73 @@ +package cd.casic.pipeline.commons.operationid.entity; + +import lombok.Data; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * @author mianbin + * @Classname SegmentBuffer + * @Description + * @Date 2025/3/18 14:16 + */ +@Data +public class SegmentBuffer { + + private String key; + /** + * 双buffer + */ + private final Segment[] segments; + /** + * 当前的使用的segment的index + */ + private volatile int currentPos; + /** + * 下一个segment是否处于可切换状态 + */ + private volatile boolean nextReady; + /** + * 是否初始化完成 + */ + private volatile boolean initOk; + /** + * 线程是否在运行中 + */ + private final AtomicBoolean threadRunning; + private final ReadWriteLock lock; + private volatile int step; + private volatile int minStep; + private volatile long updateTimestamp; + + public SegmentBuffer() { + segments = new Segment[]{new Segment(this), new Segment(this)}; + currentPos = 0; + nextReady = false; + initOk = false; + threadRunning = new AtomicBoolean(false); + lock = new ReentrantReadWriteLock(); + } + + public Segment getCurrent() { + return segments[currentPos]; + } + + public int nextPos() { + return (currentPos + 1) % 2; + } + + public void switchPos() { + currentPos = nextPos(); + } + + public Lock rLock() { + return lock.readLock(); + } + + public Lock wLock() { + return lock.writeLock(); + } +} diff --git a/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Status.java b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Status.java new file mode 100644 index 0000000..1f603f1 --- /dev/null +++ b/modules/pipeline-ci-commons/src/main/java/cd/casic/pipeline/commons/operationid/entity/Status.java @@ -0,0 +1,11 @@ +package cd.casic.pipeline.commons.operationid.entity; +/** + * @author mianbin + * @Classname Segment + * @Description 没想好干什么呢 + * @Date 2025/3/18 14:16 + */ +public enum Status { + SUCCESS, + EXCEPTION +} diff --git a/modules/pipeline-ci-event/pom.xml b/modules/pipeline-ci-event/pom.xml new file mode 100644 index 0000000..303bc75 --- /dev/null +++ b/modules/pipeline-ci-event/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-event + + + + cd.casic.pipeline + pipeline-ci-commons + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-event/src/main/java/cd/casic/pipeline/Main.java b/modules/pipeline-ci-event/src/main/java/cd/casic/pipeline/Main.java new file mode 100644 index 0000000..f17bd0b --- /dev/null +++ b/modules/pipeline-ci-event/src/main/java/cd/casic/pipeline/Main.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline; + +/** + * @author by mianbin + * @Classname ${NAME} + * @Description TODO + * @Date 2025/3/20 10:34 + */ +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/modules/pipeline-ci-log/pom.xml b/modules/pipeline-ci-log/pom.xml new file mode 100644 index 0000000..18b4f51 --- /dev/null +++ b/modules/pipeline-ci-log/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-log + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + + cd.casic.boot + spring-boot-starter-redis + + + + cd.casic.boot + spring-boot-starter-web + + + + cd.casic.boot + spring-boot-starter-monitor + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/AppLogResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/AppLogResource.java new file mode 100644 index 0000000..45d02aa --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/AppLogResource.java @@ -0,0 +1,278 @@ +package cd.casic.pipeline.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.EndPageQueryLogs; +import cd.casic.pipeline.dal.pojo.PageQueryLogs; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import static cd.casic.pipeline.commons.constant.OpsHeader.*; + + +@Tag(name = "用户-日志资源") +@RestController +@RequestMapping("/app/logs") +public interface AppLogResource { + + @Operation(summary = "根据构建ID获取初始化所有日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/") + CommonResult getInitLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount, + @Parameter(description = "第几页", required = false) + @RequestParam("page") + int page, + @Parameter(description = "每页条数", required = false) + @RequestParam("pageSize") + int pageSize + ); + + @Operation(summary = "获取更多日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/more") + CommonResult getMoreLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "日志行数", required = false) + @RequestParam(value = "num", defaultValue = "100") + int num, + @Parameter(description = "是否正序输出", required = false) + @RequestParam(value = "fromStart", defaultValue = "true") + boolean fromStart, + @Parameter(description = "起始行号", required = true) + @RequestParam(value = "start") + long start, + @Parameter(description = "结尾行号", required = true) + @RequestParam(value = "end") + long end, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount + ); + + @Operation(summary = "获取某行后的日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/after") + CommonResult getAfterLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "起始行号", required = true) + @RequestParam("start") + long start, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "获取某行前指定行数的日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/before") + CommonResult getBeforeLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "结束行号", required = true) + @RequestParam("end") + long end, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "返回日志条数", required = false) + @RequestParam("size") + int size, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "根据构建ID获取初始化最后日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/end") + CommonResult getEndLogsPage( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(value = AUTH_HEADER_USER_ID,defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "返回日志条数", required = true) + @RequestParam("size") + int size, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "根据构建ID获取初始化底部指定行数的日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/bottom") + CommonResult getBottomLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(value = AUTH_HEADER_USER_ID,defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "返回日志条数", required = false) + @RequestParam("size") + int size, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "测试接口") + @GetMapping("test") + CommonResult test( + @Parameter(description = "构建的buildId", required = true,example = "1") + @RequestParam("buildId") + String buildId, + @Parameter(description = "标签名称", required = true,example = "java") + @RequestParam("tagName") + String tagName, + @Parameter(description = "要添加子标签", required = true,example = "spring") + @RequestParam("subTag") + String subTag + ); +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/BuildLogPrintResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/BuildLogPrintResource.java new file mode 100644 index 0000000..9d3f1ba --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/BuildLogPrintResource.java @@ -0,0 +1,127 @@ +package cd.casic.pipeline.api; + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.dal.pojo.TaskBuildLogProperty; +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cd.casic.pipeline.commons.constant.OpsHeader.*; + +/** + * @author by mianbin + * @Classname BuildLogPrintResource + * @Description + * @Date 2025/3/19 14:44 + */ +@Tag(name = "构建-日志资源", description = "BUILD_LOG_PRINT") +@RestController +@RequestMapping("/build/logs") +public interface BuildLogPrintResource { + + @Operation(description = "写入一条日志") + @PostMapping("/") + CommonResult addLogLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "一条日志", required = true) + LogMessage logMessage); + + @Operation(description = "写入一条红色高亮日志") + @PostMapping("/red") + CommonResult addRedLogLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "一条日志", required = true) + LogMessage logMessage); + + @Operation(description = "写入一条黄色高亮日志") + @PostMapping("/yellow") + CommonResult addYellowLogLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "一条日志", required = true) + LogMessage logMessage + ); + + @Operation(description = "写入多条日志") + @PostMapping("/multi") + CommonResult addMultiLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "多条日志列表", required = true) + List logMessages + ); + + @Operation(description = "写入日志状态") + @PostMapping("/status") + CommonResult addLogStatus( + @Parameter(description = "构建id", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "分辨插件的tag,默认填对应插件id") + @RequestParam("tag") + String tag, + @Parameter(description = "插件内的分类的子tag,默认为空") + @RequestParam("subTag") + String subTag, + @Parameter(description = "job id或者container的34位id", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount, + @Parameter(description = "日志存储模式", required = false) + @RequestParam("logMode") + String logMode + ); + + @Operation(description = "更新日志状态") + @PutMapping("/status") + CommonResult updateLogStatus( + @Parameter(description = "构建id", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "是否已构建完成", required = true) + @RequestParam("finished") + boolean finished, + @Parameter(description = "分辨插件的tag,默认填对应插件id") + @RequestParam("tag") + String tag, + @Parameter(description = "插件内的分类的子tag,默认为空") + @RequestParam("subTag") + String subTag, + @Parameter(description = "job id或者container的34位id", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount, + @Parameter(description = "日志存储模式", required = false) + @RequestParam("logMode") + String logMode + ); + + @Operation(description = "更新日志存储模式的流转状态") + @PostMapping("/mode") + CommonResult updateLogStorageMode( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "执行次数") + @RequestParam("executeCount") + int executeCount, + @Parameter(description = "所有插件的日志存储结果", required = true) + List propertyList + ); + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/OpLogResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/OpLogResource.java new file mode 100644 index 0000000..94f83d5 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/OpLogResource.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "管理-日志资源") +@RestController +@RequestMapping("/op") +public interface OpLogResource { + @Operation(description = "执行搬冷任务") + @PutMapping("/es/index/cold") + CommonResult makeIndexCold(); +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogPrintResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogPrintResource.java new file mode 100644 index 0000000..acbea24 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogPrintResource.java @@ -0,0 +1,86 @@ +package cd.casic.pipeline.api; + + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.enums.LogStorageMode; +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cd.casic.pipeline.commons.constant.OpsHeader.AUTH_HEADER_DEVOPS_BUILD_ID; + + +@RestController +@Tag(name = "服务-日志打印资源") +@RequestMapping("/service/logs/print") +public interface ServiceLogPrintResource { + + @Operation(summary = "写入日志状态") + @PostMapping("/status") + @Parameters({ + @Parameter(name = "tag", description = "分辨插件的tag,默认填对应插件id"), + @Parameter(name = "subTag", description = "插件内的分类的子tag,默认为空"), + @Parameter(name = "jobId", description = "job id或者container的34位id"), + @Parameter(name = "executeCount", description = "执行次数"), + + }) + CommonResult addLogStatus(@RequestHeader(value = AUTH_HEADER_DEVOPS_BUILD_ID) + @Parameter(description = "构建ID", required = true) + String buildId, + @RequestParam(value = "tag", required = false) String tag, + @RequestParam(value = "subTag", required = false) String subTag, + @RequestParam(value = "jobId", required = false) String jobId, + @RequestParam(value = "executeCount", required = false, defaultValue = "1") int executeCount); + + @Operation(summary = "更新日志状态") + @PutMapping("/status") + CommonResult updateLogStatus( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "是否已构建完成", required = true) + @RequestParam("finished") + boolean finished, + @Parameter(description = "分辨插件的tag,默认填对应插件id") + @RequestParam(value = "tag", required = false) + String tag, + @Parameter(description = "插件内的分类的子tag,默认为空") + @RequestParam(value = "subTag", required = false) + String subTag, + @Parameter(description = "job id或者container的34位id") + @RequestParam(value = "jobId", required = false) + String jobId, + @Parameter(description = "执行次数") + @RequestParam(value = "executeCount", required = false, defaultValue = "1") + int executeCount, + @Parameter(description = "插件的存储模式") + @RequestParam(value = "logStorageMode", required = false) + LogStorageMode logStorageMode + ); + + @Operation(summary = "写入一条日志") + @PostMapping("/") + CommonResult addLogLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + @Parameter(description = "一条日志", required = true) + LogMessage logMessage); + + @Operation(summary = "写入多条日志") + @PostMapping("/multi") + CommonResult addLogMultiLine( + @Parameter(description = "构建ID", required = true) + @RequestHeader(AUTH_HEADER_DEVOPS_BUILD_ID) + String buildId, + + @Parameter(description = "多条日志列表", required = true) + List logMessages); + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogResource.java new file mode 100644 index 0000000..a06d2da --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/ServiceLogResource.java @@ -0,0 +1,173 @@ +package cd.casic.pipeline.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.QueryLogLineNum; +import cd.casic.pipeline.dal.pojo.QueryLogStatus; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import static cd.casic.pipeline.commons.constant.OpsHeader.*; + + +@RestController +@Tag(name = "服务-日志资源") +@RequestMapping("/service/logs") +public interface ServiceLogResource { + + @Operation(summary = "根据构建ID获取初始化所有日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/") + CommonResult getInitLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount + ); + + @Operation(summary = "获取更多日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/more") + CommonResult getMoreLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "日志行数", required = false) + @RequestParam(value = "num", defaultValue = "100") + int num, + @Parameter(description = "是否正序输出", required = false) + @RequestParam(value = "fromStart", defaultValue = "true") + boolean fromStart, + @Parameter(description = "起始行号", required = true) + @RequestParam(value = "start") + long start, + @Parameter(description = "结尾行号", required = true) + @RequestParam(value = "end") + long end, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount + ); + + @Operation(summary = "获取某行前的日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/after") + CommonResult getAfterLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "起始行号", required = true) + @RequestParam("start") + long start, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "获取插件的的日志状态") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/mode") + CommonResult getLogMode( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "对应elementId", required = true) + @RequestParam("tag") + String tag, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "获取当前构建的最大行号") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/last_line_num") + CommonResult getLogLastLineNum( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId + ); + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/UserLogResource.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/UserLogResource.java new file mode 100644 index 0000000..2ac860a --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/UserLogResource.java @@ -0,0 +1,195 @@ +package cd.casic.pipeline.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.QueryLogStatus; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import static cd.casic.pipeline.commons.constant.OpsHeader.*; + + +@RestController +@Tag(name = "用户-日志资源") +@RequestMapping("/user/logs") +public interface UserLogResource { + @Operation(summary = "根据构建ID获取初始化所有日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/") + CommonResult getInitLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam(value = "subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount + ); + + @Operation(summary = "获取更多日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/more") + CommonResult getMoreLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug", defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType", defaultValue = "null") + LogType logType, + @Parameter(description = "日志行数", required = false) + @RequestParam(value = "num", defaultValue = "100") + int num, + @Parameter(description = "是否正序输出", required = false) + @RequestParam(value = "fromStart", defaultValue = "true") + boolean fromStart, + @Parameter(description = "起始行号", required = true) + @RequestParam(value = "start") + long start, + @Parameter(description = "结尾行号", required = true) + @RequestParam(value = "end") + long end, + @Parameter(description = "对应elementId", required = false) + @RequestParam(value = "tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam(value = "subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam(value = "jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam(value = "executeCount") + int executeCount + ); + + @Operation(summary = "获取某行后的日志") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/after") + CommonResult getAfterLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "起始行号", required = true) + @RequestParam("start") + long start, + @Parameter(description = "是否包含调试日志", required = false) + @RequestParam(value = "debug",defaultValue = "false") + boolean debug, + @Parameter(description = "过滤日志级别", required = false) + @RequestParam(value = "logType",defaultValue = "null") + LogType logType, + @Parameter(description = "对应elementId", required = false) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); + + @Operation(summary = "下载日志接口") + @GetMapping("{projectId}/{pipelineId}/{buildId}/download") + ResponseEntity downloadLogs( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "对应elementId", required = true) + @RequestParam("tag") + String tag, + @Parameter(description = "指定subTag", required = false) + @RequestParam("subTag") + String subTag, + @Parameter(description = "对应jobId", required = false) + @RequestParam("jobId") + String jobId, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount, + @Parameter(description = "文件名") + @RequestParam("fileName") + String fileName + ); + + @Operation(summary = "获取插件的的日志状态") + @GetMapping("/{projectId}/{pipelineId}/{buildId}/mode") + CommonResult getLogMode( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @RequestHeader(AUTH_HEADER_USER_ID) + String userId, + @Parameter(description = "项目ID", required = true) + @PathVariable("projectId") + String projectId, + @Parameter(description = "流水线ID", required = true) + @PathVariable("pipelineId") + String pipelineId, + @Parameter(description = "构建ID", required = true) + @PathVariable("buildId") + String buildId, + @Parameter(description = "对应elementId", required = true) + @RequestParam("tag") + String tag, + @Parameter(description = "执行次数", required = false) + @RequestParam("executeCount") + int executeCount + ); +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/AppLogResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/AppLogResourceImpl.java new file mode 100644 index 0000000..85be563 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/AppLogResourceImpl.java @@ -0,0 +1,61 @@ +package cd.casic.pipeline.api.impl; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.AppLogResource; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.EndPageQueryLogs; +import cd.casic.pipeline.dal.pojo.PageQueryLogs; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import cd.casic.pipeline.service.BuildLogQueryService; +import cd.casic.pipeline.service.LogTagService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@Slf4j +public class AppLogResourceImpl implements AppLogResource { + + @Resource + private BuildLogQueryService buildLogQueryService; + @Resource + private LogTagService logTagService; + + @Override + public CommonResult getInitLogs(String userId, String projectId, String pipelineId, String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount, int page, int pageSize) { + return buildLogQueryService.getInitLogsPage(userId, projectId, pipelineId, buildId, debug, logType, tag, jobId, executeCount, page, pageSize, subTag); + } + + @Override + public CommonResult getMoreLogs(String userId, String projectId, String pipelineId, String buildId, boolean debug, LogType logType, int num, boolean fromStart, long start, long end, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getMoreLogs(userId, projectId, pipelineId, buildId, debug, logType, num, fromStart, start, end, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult getAfterLogs(String userId, String projectId, String pipelineId, String buildId, long start, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getAfterLogs(userId, projectId, pipelineId, buildId, start, debug, logType, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult getBeforeLogs(String userId, String projectId, String pipelineId, String buildId, long end, boolean debug, LogType logType, int size, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getBeforeLogs(userId, projectId, pipelineId, buildId, end, debug, logType, size, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult getEndLogsPage(String userId, String projectId, String pipelineId, String buildId, int size, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getEndLogsPage(userId, projectId, pipelineId, buildId, size, debug, logType, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult getBottomLogs(String userId, String projectId, String pipelineId, String buildId, boolean debug, LogType logType, int size, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getBottomLogs(userId, projectId, pipelineId, buildId, size, debug, logType, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult test(String buildId, String tagName, String subTag) { + logTagService.saveSubTag(buildId, tagName, subTag); + return CommonResult.success("成功"); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/BuildLogPrintResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/BuildLogPrintResourceImpl.java new file mode 100644 index 0000000..f82218a --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/BuildLogPrintResourceImpl.java @@ -0,0 +1,126 @@ +package cd.casic.pipeline.api.impl; + + +import cd.casic.framework.commons.exception.ErrorCode; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.BuildLogPrintResource; +import cd.casic.pipeline.enums.LogStorageMode; +import cd.casic.pipeline.dal.pojo.meta.Ansi; +import cd.casic.pipeline.dal.pojo.TaskBuildLogProperty; +import cd.casic.pipeline.service.BuildLogPrintService; +import cd.casic.pipeline.service.IndexService; +import cd.casic.pipeline.service.LogStatusService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.factory.annotation.Value; +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@RestController +public class BuildLogPrintResourceImpl implements BuildLogPrintResource { + @Resource + private BuildLogPrintService buildLogPrintService; + @Resource + private LogStatusService logStatusService; + @Resource + private IndexService indexService; + + @Value("{$spring.application.name}") + private String applicationName; + + @Override + public CommonResult addLogLine(String buildId, LogMessage logMessage) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + ArrayList list = new ArrayList<>(); + list.add(logMessage); + //buildLogPrintService.dispatchEvent(new LogOriginEvent(buildId, list)); + System.out.println("占位"); + return CommonResult.success(true); + } + + @Override + public CommonResult addRedLogLine(String buildId, LogMessage logMessage) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + // 设置红色日志 + List list = new ArrayList<>(); + logMessage.setMessage(new Ansi().bold().fgRed().a(logMessage.getMessage()).reset().toString()); + list.add(logMessage); + //buildLogPrintService.dispatchEvent(new LogOriginEvent(buildId,list)); + System.out.println("占位"); + return CommonResult.success(true); + } + + @Override + public CommonResult addYellowLogLine(String buildId, LogMessage logMessage) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + // 设置黄色日志 + List list = new ArrayList<>(); + logMessage.setMessage(new Ansi().bold().fgYellow().a(logMessage.getMessage()).reset().toString()); + list.add(logMessage); + //buildLogPrintService.dispatchEvent(new LogOriginEvent(buildId,list)); + System.out.println("占位" + buildId + list); + return CommonResult.success(true); + } + + @Override + public CommonResult addMultiLine(String buildId, List logMessages) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + //buildLogPrintService.dispatchEvent(new LogOriginEvent(buildId,logMessages)); + System.out.println("占位" + buildId + logMessages); +// recordMultiLogCount(logMessages.size()); + return CommonResult.success(true); + } + + @Override + public CommonResult addLogStatus(String buildId, String tag, String subTag, String jobId, int executeCount, String logMode) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + // #7168 通过一次获取创建记录以及缓存 + String index = indexService.getIndexName(buildId); + log.info("Start to print log to index[" + index + "]"); + //buildLogPrintService.dispatchEvent(new LogStatusEvent(buildId,false,tag,subTag,jobId,executeCount, LogStorageMode.parse(logMode))); + System.out.println("占位" + buildId + tag + subTag + jobId + executeCount + LogStorageMode.parse(logMode)); + return CommonResult.success(true); + } + + @Override + public CommonResult updateLogStatus(String buildId, boolean finished, String tag, String subTag, String jobId, int executeCount, String logMode) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + //buildLogPrintService.dispatchEvent(new LogStatusEvent(buildId,finished,tag,subTag,jobId,executeCount,LogStorageMode.parse(logMode))); + System.out.println("占位" + buildId + finished + tag + subTag + jobId + executeCount + LogStorageMode.parse(logMode)); + return CommonResult.success(true); + } + + @Override + public CommonResult updateLogStorageMode(String buildId, int executeCount, List propertyList) { + if (Strings.isBlank(buildId)) { + log.warn("Invalid build ID[" + buildId + "]"); + return CommonResult.error(new ErrorCode(1000, "buildId为空")); + } + logStatusService.updateStorageMode(buildId, executeCount, propertyList); + return CommonResult.success(true); + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/OpLogResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/OpLogResourceImpl.java new file mode 100644 index 0000000..87e4dcf --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/OpLogResourceImpl.java @@ -0,0 +1,16 @@ +package cd.casic.pipeline.api.impl; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.OpLogResource; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class OpLogResourceImpl implements OpLogResource { + // todo 和ES数据库相关的冷处理 + @Override + public CommonResult makeIndexCold() { + return null; + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogPrintResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogPrintResourceImpl.java new file mode 100644 index 0000000..ab20a65 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogPrintResourceImpl.java @@ -0,0 +1,83 @@ +package cd.casic.pipeline.api.impl; + + +import cd.casic.framework.commons.exception.ErrorCode; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.ServiceLogPrintResource; +import cd.casic.pipeline.enums.LogStorageMode; +import cd.casic.pipeline.event.log.LogOriginEvent; +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import cd.casic.pipeline.service.BuildLogPrintService; +import cd.casic.pipeline.service.IndexService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@RestController +public class ServiceLogPrintResourceImpl implements ServiceLogPrintResource { + + @Resource + private IndexService indexService; + @Resource + private BuildLogPrintService buildLogPrintService; + + private static Logger logger = LoggerFactory.getLogger(ServiceLogPrintResourceImpl.class); + + @Override + public CommonResult addLogStatus(String buildId, String tag, String subTag, String jobId, int executeCount) { + // 判断 buildId 是否为空 + if (buildId.isEmpty()) { + logger.warn("Invalid build ID"); + return CommonResult.error(new ErrorCode(1000, "Invalid build ID")); + } + // 通过一次获取 创建记录以及缓存 + String index = indexService.getIndexName(buildId); + logger.info("Start to print log to index: " + index); +// buildLogPrintService.dispatchEvent( +// new LogStatusEvent(buildId, false, tag, subTag, jobId, executeCount) +// ); + return CommonResult.success(true); + } + + @Override + public CommonResult updateLogStatus(String buildId, boolean finished, String tag, + String subTag, String jobId, int executeCount, LogStorageMode logStorageMode) { + if (Strings.isBlank(buildId)) { + logger.warn("Invalid build ID:" + buildId); + return CommonResult.error(new ErrorCode(1000, "Invalid build ID")); + } +// buildLogPrintService.dispatchEvent( +// new LogStatusEvent(buildId,finished,tag,subTag,jobId,executeCount,logStorageMode) +// ); + return CommonResult.success(true); + } + + @Override + public CommonResult addLogLine(String buildId, LogMessage logMessage) { + if (Strings.isBlank(buildId)) { + logger.warn("Invalid build ID" + buildId); + return CommonResult.error(new ErrorCode(1000, "Invalid build ID")); + } + List messages = new ArrayList<>(); + messages.add(logMessage); + return buildLogPrintService.asyncDispatchEvent(new LogOriginEvent(buildId, messages)); + } + + @Override + public CommonResult addLogMultiLine(String buildId, List logMessages) { + if (Strings.isBlank(buildId)) { + logger.warn("Invalid build ID" + buildId); + return CommonResult.error(new ErrorCode(1000, "Invalid build ID")); + } + buildLogPrintService.asyncDispatchEvent(new LogOriginEvent(buildId, logMessages)); + return CommonResult.success(true); + } + + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogResourceImpl.java new file mode 100644 index 0000000..e2c8888 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/ServiceLogResourceImpl.java @@ -0,0 +1,51 @@ +package cd.casic.pipeline.api.impl; + + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.ServiceLogResource; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.QueryLogLineNum; +import cd.casic.pipeline.dal.pojo.QueryLogStatus; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import cd.casic.pipeline.service.BuildLogQueryService; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class ServiceLogResourceImpl implements ServiceLogResource { + + @Resource + private BuildLogQueryService buildLogQueryService; + + private static int defaultNum = 100; + + @Override + public CommonResult getInitLogs(String userId, String projectId, String pipelineId, String buildId, + boolean debug, LogType logType, String tag, String jobId, int executeCount) { + return buildLogQueryService.getInitLogs(userId,projectId,pipelineId,buildId,debug,logType,tag,jobId,executeCount,null); + } + + @Override + public CommonResult getMoreLogs(String userId, String projectId, String pipelineId, String buildId, + boolean debug, LogType logType, int num, boolean fromStart, long start, long end, String tag, String jobId, int executeCount) { + return buildLogQueryService.getMoreLogs(userId,projectId,pipelineId,buildId,debug,logType,num,fromStart,start,end,tag,jobId,executeCount,null); + } + + @Override + public CommonResult getAfterLogs(String userId, String projectId, String pipelineId, String buildId,long start, + boolean debug, LogType logType,String tag,String jobId, int executeCount) { + return buildLogQueryService.getAfterLogs(userId,projectId,pipelineId,buildId,start,debug,logType,tag,jobId,executeCount,null); + } + + @Override + public CommonResult getLogMode(String userId, String projectId, String pipelineId, String buildId, String tag, int executeCount) { + return buildLogQueryService.getLogMode(userId, projectId, pipelineId, buildId,tag,executeCount); + } + + @Override + public CommonResult getLogLastLineNum(String userId, String projectId, String pipelineId, String buildId) { + return buildLogQueryService.getLastLineNum(userId, projectId, pipelineId, buildId); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/UserLogResourceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/UserLogResourceImpl.java new file mode 100644 index 0000000..aa992d5 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/api/impl/UserLogResourceImpl.java @@ -0,0 +1,82 @@ +package cd.casic.pipeline.api.impl; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.UserLogResource; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.dal.pojo.LogLine; +import cd.casic.pipeline.dal.pojo.QueryLogStatus; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import cd.casic.pipeline.service.BuildLogQueryService; +import io.micrometer.core.annotation.Timed; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +@RestController +public class UserLogResourceImpl implements UserLogResource { + @Resource + private BuildLogQueryService buildLogQueryService; + @Resource + private MeterRegistry meterRegistry; + + private static final int defaultNum = 100; + + @Value("${spring.application.name}") + private String applicationName = ""; + + @Override + @Timed + public CommonResult getInitLogs(String userId, String projectId, String pipelineId, + String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + CommonResult initLogs = buildLogQueryService.getInitLogs(userId, projectId, pipelineId, buildId, debug, logType, tag, jobId, executeCount, subTag); + List logs = initLogs.getData().getLogs(); + if (logs == null) { + recordListLogCount(0); + } else { + recordListLogCount(logs.size()); + } + return initLogs; + } + + @Override + public CommonResult getMoreLogs(String userId, String projectId, String pipelineId, + String buildId, boolean debug, LogType logType, int num, boolean fromStart, long start, long end, String tag, String subTag, String jobId, int executeCount) { + return buildLogQueryService.getMoreLogs(userId, projectId, pipelineId, buildId, debug, logType, num, fromStart, start, end, tag, jobId, executeCount, subTag); + } + + @Override + public CommonResult getAfterLogs(String userId, String projectId, String pipelineId, String buildId, long start, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + CommonResult afterLogs = buildLogQueryService.getAfterLogs(userId, projectId, + pipelineId, buildId, start, debug, logType, tag, jobId, executeCount, subTag); + List logs = afterLogs.getData().getLogs(); + if (logs == null) { + recordListLogCount(0); + } else { + recordListLogCount(logs.size()); + } + return afterLogs; + } + + @Override + public ResponseEntity downloadLogs(String userId, String projectId, String pipelineId, String buildId, String tag, String subTag, String jobId, int executeCount, String fileName) { + return buildLogQueryService.downloadLogs(userId, projectId, pipelineId, buildId, tag, jobId, executeCount, fileName, subTag); + } + + @Override + public CommonResult getLogMode(String userId, String projectId, String pipelineId, String buildId, String tag, int executeCount) { + return buildLogQueryService.getLogMode(userId, projectId, pipelineId, buildId, tag, executeCount); + } + + private void recordListLogCount(int count) { + Counter.builder("list_log_count") + .tag("application", applicationName) + .register(meterRegistry) + .increment(count); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/config/BuildLogPrinter.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/config/BuildLogPrinter.java new file mode 100644 index 0000000..93d47ef --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/config/BuildLogPrinter.java @@ -0,0 +1,22 @@ +package cd.casic.pipeline.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; + +/** + * @author by mianbin + * @Classname BuildLogPrinter + * @Description 输出构建日志 + * @Date 2025/3/19 14:40 + */ +@Slf4j +@Configuration +public class BuildLogPrinter { + private static String LOG_DEBUG_FLAG = "##[debug]"; + + private static String LOG_ERROR_FLAG = "##[error]"; + + private static String LOG_WARN_FLAG = "##[warning]"; + + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/IndexMapper.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/IndexMapper.java new file mode 100644 index 0000000..57f5f61 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/IndexMapper.java @@ -0,0 +1,50 @@ +package cd.casic.pipeline.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.dal.dataobject.LogIndicesV2; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Date; +import java.util.Objects; + +/** + * @author by mianbin + * @Classname IndexDao + * @Description LogIndicesV2 的mapper + * @Date 2025/3/20 10:07 + */ +@Mapper +public interface IndexMapper extends BaseMapperX { + default void create(String buildId, String indexName, boolean enable) { + Date now = new Date(); + LogIndicesV2 entity = new LogIndicesV2(buildId, indexName, 1, now, now, enable, true); + insert(entity); + } + + /** + * 通过 id 查找 LogIndicesV2 + * 该方法是可能返回 null 值的,所以调用该方法的时候都应该对 null 值进行判断 + * + * @param buildId + * @return + */ + default LogIndicesV2 getBuild(String buildId) { + return selectOne(Wrappers.lambdaQuery().eq(LogIndicesV2::getBuildId, buildId)); + } + + default String getIndexName(String buildId) { + LogIndicesV2 logIndices = getBuild(buildId); + if (logIndices == null) + return ""; + return logIndices.getIndexName(); + } + + default boolean updateLastLineNum(String buildId, long latestLineNum) { + LogIndicesV2 logIndicesV2 = selectOne(LogIndicesV2::getBuildId, buildId); + if (Objects.nonNull(logIndicesV2)) { + logIndicesV2.setLastLineNum(latestLineNum); + } + return insertOrUpdate(logIndicesV2); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogStatusMapper.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogStatusMapper.java new file mode 100644 index 0000000..c3228c8 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogStatusMapper.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.dal.dataobject.LogStatus; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author by mianbin + * @Classname LogStatus + * @Description TODO + * @Date 2025/3/20 14:28 + */ +@Mapper +public interface LogStatusMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogTahMapper.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogTahMapper.java new file mode 100644 index 0000000..5b83a36 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dao/LogTahMapper.java @@ -0,0 +1,45 @@ +package cd.casic.pipeline.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.dal.dataobject.LogSubTags; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @author by mianbin + * @Classname LogTahMapper + * @Description TODO + * @Date 2025/3/20 10:13 + */ +@Mapper +public interface LogTahMapper extends BaseMapperX { + + default void save(String buildId, String tag, String subTags) { + LogSubTags logSubTags = new LogSubTags(buildId, tag, subTags); + insert(logSubTags); + // todo 如果存在的话就更新值 + } + + default String getSubTags(String buildId, String tag) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(LogSubTags::getBuildId, buildId) + .eq(LogSubTags::getTag, tag); + LogSubTags one = selectOne(wrapper); + if (one != null) { + return one.getSubTags(); + } + return null; + } + + /** + * 删除所有 deleteList 里面的 buildId 构造的日志 + */ + default void delete(List deleteList) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(LogSubTags::getBuildId, deleteList); + delete(wrapper); + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogIndicesV2.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogIndicesV2.java new file mode 100644 index 0000000..9a5072e --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogIndicesV2.java @@ -0,0 +1,55 @@ +package cd.casic.pipeline.dal.dataobject; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * @author by mianbin + * @Classname LogIndicesV2 + * @Description TODO + * @Date 2025/3/19 17:16 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "log_indices_v2", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class LogIndicesV2 extends BaseDO { + @TableId + private Long id; + + private String buildId; + + private String indexName; + + private long lastLineNum; + /** + * build is enable v2 or not + */ + private boolean enable; + /** + * multi es log cluster name + */ + private String logClusterName; + /** + * use multi es log cluster or not + */ + private boolean useCluster; + + public LogIndicesV2(String buildId, String indexName, long lastLineNum, Date createTime, Date updateTime, boolean enable, boolean useCluster) { + this.buildId = buildId; + this.indexName = indexName; + this.lastLineNum = lastLineNum; + this.enable = enable; + this.useCluster = useCluster; + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogStatus.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogStatus.java new file mode 100644 index 0000000..5198926 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogStatus.java @@ -0,0 +1,49 @@ +package cd.casic.pipeline.dal.dataobject; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +/** + * @author by mianbin + * @Classname LogStatus + * @Description TODO + * @Date 2025/3/19 17:24 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@TableName(value = "log_status", autoResultMap = true) +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class LogStatus extends BaseDO { + @TableId + private Long id; + + private String buildId; + + private String tag; + + private String subTag; + + private String jobId; + + private String mode; + + private int executeCount; + + private Boolean finished; + + public LogStatus(String buildId, String tag, String subTag, String jobId, String mode, int executeCount, Boolean finished) { + this.buildId = buildId; + this.tag = tag; + this.subTag = subTag; + this.jobId = jobId; + this.mode = mode; + this.executeCount = executeCount; + this.finished = finished; + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogSubTags.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogSubTags.java new file mode 100644 index 0000000..50bfa02 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/dataobject/LogSubTags.java @@ -0,0 +1,44 @@ +package cd.casic.pipeline.dal.dataobject; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +/** + * @author by mianbin + * @Classname LogSubTags + * @Description TODO + * @Date 2025/3/19 17:31 + */ +@Data +@Accessors(chain = true) +@TableName(value = "log_sub_tags", autoResultMap = true) +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class LogSubTags extends BaseDO { + @TableId + private long id; + /** + * 构建ID + */ + private String buildId; + + /** + * 插件标签 + */ + private String tag; + + /** + * 插件子标签 + */ + private String subTags; + + public LogSubTags(String buildId, String tag, String subTags) { + this.buildId = buildId; + this.tag = tag; + this.subTags = subTags; + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/EndPageQueryLogs.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/EndPageQueryLogs.java new file mode 100644 index 0000000..d13d583 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/EndPageQueryLogs.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.enums.LogStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.util.ArrayList; +import java.util.List; + +/** + * @author by mianbin + * @Classname EndPageQueryLogs + * @Date 2025/3/19 17:34 + */ +@Data +@Schema(title = "结尾的日志查询模型") +public class EndPageQueryLogs { + @Schema(description = "构建ID", required = true) + private String buildId; + @Schema(description = "开始行号", required = true) + private long startLineNo = 0L; + @Schema(description = "结束行号", required = true) + private long endLineNo = 0L; + @Schema(description = "日志列表", required = true) + private List logs = new ArrayList<>(); + @Schema(description = "所用时间", required = false) + private long timeUsed = 0; + @Schema(description = "日志查询状态", required = false) + private int status = LogStatusEnum.SUCCEED.status; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/LogLine.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/LogLine.java new file mode 100644 index 0000000..3cd6303 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/LogLine.java @@ -0,0 +1,41 @@ +package cd.casic.pipeline.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * @author by mianbin + * @Classname LogLine + * @Date 2025/3/19 17:35 + */ +@Data +@Schema(title = "日志模型") +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = false) +public class LogLine { + + @Schema(description = "日志行号", required = true) + private long lineNo; + @Schema(description = "日志时间戳", required = true) + private long timestamp; + @Schema(description = "日志消息体", required = true) + private String message; + @Schema(description = "日志权重级", required = true) + private Byte priority = 0; + @Schema(description = "日志tag", required = true) + private String tag = ""; + @Schema(description = "日志子tag", required = true) + private String subTag = ""; + @Schema(description = "日志jobId", required = true) + private String jobId = ""; + @Schema(description = "日志执行次数", required = true) + private int executeCount = 1; + + @Override + public int hashCode() { + return (int) (lineNo ^ (lineNo >>> 32)); + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/PageQueryLogs.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/PageQueryLogs.java new file mode 100644 index 0000000..b7d0704 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/PageQueryLogs.java @@ -0,0 +1,27 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.framework.commons.pojo.PageResult; +import cd.casic.pipeline.enums.LogStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author by mianbin + * @Classname PageQueryLogs + * @Date 2025/3/19 17:39 + */ +@Data +@Schema(title = "日志查询模型") +public class PageQueryLogs { + @Schema(description = "构建ID", required = true) + String buildId; + @Schema(description = "是否结束", required = true) + boolean finished; + //todo Page分页类,分页数据包装模型 + @Schema(description = "日志列表", required = true) + PageResult logs; + @Schema(description = "所用时间", required = false) + long timeUsed = 0; + @Schema(description = "日志查询状态", required = false) + int status = LogStatusEnum.SUCCEED.status; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogLineNum.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogLineNum.java new file mode 100644 index 0000000..346fdf1 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogLineNum.java @@ -0,0 +1,24 @@ +package cd.casic.pipeline.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author by mianbin + * @Classname QueryLogLineNum + * @Date 2025/3/19 17:47 + */ +@Data +@Schema(title = "日志行号查询模型") +@AllArgsConstructor +@NoArgsConstructor +public class QueryLogLineNum { + @Schema(description = "构建ID", required = true) + String buildId; + @Schema(description = "是否结束", required = true) + boolean finished; + @Schema(description = "日志存储状态", required = false) + long lastLineNum; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogStatus.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogStatus.java new file mode 100644 index 0000000..b1db4b7 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogStatus.java @@ -0,0 +1,23 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.enums.LogStorageMode; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author by mianbin + * @Classname QueryLogStatus + * @Date 2025/3/19 17:45 + */ +@Data +@AllArgsConstructor +@Schema(description = "日志状态查询模型") +public class QueryLogStatus { + @Schema(description = "构建ID", required = true) + private String buildId; + @Schema(description = "是否结束", required = true) + private boolean finished; + @Schema(description = "日志存储状态") + private LogStorageMode logMode; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogs.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogs.java new file mode 100644 index 0000000..1f0e282 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/QueryLogs.java @@ -0,0 +1,35 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.enums.LogStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author by mianbin + * @Classname QueryLogs + * @Date 2025/3/19 17:48 + */ +@Data +@Schema(description = "日志查询模型") +public class QueryLogs { + @Schema(description = "构建ID", required = true) + private String buildId; + @Schema(description = "是否结束", required = true) + private boolean finished; + @Schema(description = "是否有后续日志") + private boolean hasMore = false; + @Schema(description = "日志列表", required = true) + // listOf() 不可变 ; mutableListOf 生成可变数组 + private List logs = new ArrayList<>(); + @Schema(description = "所用时间", required = false) + private long timeUsed = 0; + @Schema(description = "日志查询状态", required = false) + private int status = LogStatusEnum.SUCCEED.status; + @Schema(description = "日志子tag列表", required = false) + private List subTags = null; + @Schema(description = "错误信息", required = false) + private String message = null; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/TaskBuildLogProperty.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/TaskBuildLogProperty.java new file mode 100644 index 0000000..51ea9b5 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/TaskBuildLogProperty.java @@ -0,0 +1,27 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.enums.LogStorageMode; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.File; + +/** + * @author by mianbin + * @Classname TaskBuildLogProperty + * @Date 2025/3/19 17:48 + */ +@Data +@Schema(description = "任务构建日志属性") +public class TaskBuildLogProperty { + @Schema(description = "插件任务ID", required = true) + public String elementId; + @Schema(description = "日志文件子路径", required = true) + public String childPath; + @Schema(description = "日志zip文件子路径", required = true) + public String childZipPath; + @Schema(description = "日志文件句柄", required = true) + public File logFile; + @Schema(description = "日志的存储模式") + public LogStorageMode logStorageMode = LogStorageMode.UPLOAD; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessage.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessage.java new file mode 100644 index 0000000..4cf7374 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessage.java @@ -0,0 +1,34 @@ +package cd.casic.pipeline.dal.pojo.message; + +import cd.casic.pipeline.enums.LogType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author by mianbin + * @Classname LogMessage + * @Description 日志模型 + * @Date 2025/3/19 17:13 + */ +@Data +@Schema(title = "日志模型") +@AllArgsConstructor +public class LogMessage { + + @Schema(description = "日志内容信息") + String message; + @Schema(description = "时间戳") + long timestamp; + @Schema(description = "标签") + String tag = ""; + @Schema(description = "job id") + String jobId = ""; + @Schema(description = "日志类型") + LogType logType = LogType.LOG; + @Schema(description = "执行次数") + int executeCount; + @Schema(description = "子标签") + String subTag = null; + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessageWithLineNo.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessageWithLineNo.java new file mode 100644 index 0000000..eb4dc5d --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/message/LogMessageWithLineNo.java @@ -0,0 +1,25 @@ +package cd.casic.pipeline.dal.pojo.message; + +import cd.casic.pipeline.enums.LogType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author by mianbin + * @Classname LogMessageWithLineNo + * @Date 2025/3/19 17:14 + */ +@Data +@Schema(title = "带行号的日志消息") +@AllArgsConstructor +public class LogMessageWithLineNo { + private String tag; + private String jobId = ""; + private String subTag = null; + private String message; + private long timestamp = 0; + private LogType logType = LogType.LOG; + private long lineNo = 0; + private int executeCount = 1; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/Ansi.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/Ansi.java new file mode 100644 index 0000000..ee2db4f --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/Ansi.java @@ -0,0 +1,133 @@ +package cd.casic.pipeline.dal.pojo.meta; + +import org.apache.logging.log4j.util.Strings; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +public class Ansi { + private static char FIRST_ESC_CHAR = 27; + private static char SECOND_ESC_CHAR = '['; + private static String DISABLE = Ansi.class.getName() + ".disable"; + private static Callable detector; + private StringBuilder builder; + + private List attributeOptions = new ArrayList<>(5); + + public void newDetector(Callable detector) { + if (detector == null) { + throw new IllegalArgumentException("detector is null"); + } + this.detector = detector; + } + + public boolean isDetected() { + try { + return detector.call(); + } catch (Exception e) { + return true; + } + } + + private InheritableThreadLocal holder = new InheritableThreadLocal() { + @Override + public Boolean initialValue(){ + return isDetected(); + } + }; + + public Ansi bold() { + return a(AnsiAttribute.INTENSITY_BOLD); + } + + public Ansi a(AnsiAttribute attribute) { + attributeOptions.add(attribute.value); + return this; + } + + public Ansi fgYellow() { + return this.fg(AnsiColor.YELLOW); + } + + public Ansi fgGreen() { + return this.fg(AnsiColor.GREEN); + } + + public Ansi fgRed() { + return this.fg(AnsiColor.RED); + } + + public Ansi fg(AnsiColor color) { + attributeOptions.add(color.fg()); + return this; + } + + public Ansi a(String value) { + // 修复换行后ansi编码问题 + String strLF = innerAppendEscapeSequenceStr('m', attributeOptions); + // 清空属性??? + flushAttributes(); + // 对value进行正则替换 + String fixLF = ""; + // 对 value 的空安全判断 + if (!Strings.isBlank(value)) + fixLF = value.replace("\n", "\n$strLF"); + builder.append(fixLF); + return this; + } + + private void flushAttributes() { + if (attributeOptions.isEmpty()) { + return; + } + if (attributeOptions.size() == 1 && attributeOptions.get(0) == 0) { + builder.append(FIRST_ESC_CHAR); + builder.append(SECOND_ESC_CHAR); + builder.append('m'); + } else { + // 内部添加分号 + innerAppendEscapeSequence('m', attributeOptions); + } + attributeOptions.clear(); + } + + private Ansi innerAppendEscapeSequence(char command, List options) { + builder.append(FIRST_ESC_CHAR); + builder.append(SECOND_ESC_CHAR); + int size = options.size(); + for (int i = 0;i < size;i++) { + if (i != 0) { + builder.append(';'); + } + builder.append(options.get(i)); + } + builder.append(command); + return this; + } + + private String innerAppendEscapeSequenceStr(char command,List options) { + StringBuilder str = new StringBuilder(); + str.append(FIRST_ESC_CHAR); + str.append(SECOND_ESC_CHAR); + int size = options.size(); + for (int i = 0; i < size;i++) { + if (i != 0) { + str.append(';'); + } + str.append(options.get(i)); + } + str.append(command); + return str.toString(); + } + + public Ansi reset() { + return a(AnsiAttribute.RESET); + } + + @Override + public String toString() { + flushAttributes(); + return builder.toString(); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiAttribute.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiAttribute.java new file mode 100644 index 0000000..2ddcb75 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiAttribute.java @@ -0,0 +1,28 @@ +package cd.casic.pipeline.dal.pojo.meta; + +public enum AnsiAttribute { + RESET(0), + INTENSITY_BOLD(1), + INTENSITY_FAINT(2), + ITALIC(3), + UNDERLINE(4), + BLINK_SLOW(5), + BLINK_FAST(6), + NEGATIVE_ON(7), + CONCEAL_ON(8), + STRIKETHROUGH_ON(9), + UNDERLINE_DOUBLE(21), + INTENSITY_BOLD_OFF(22), + ITALIC_OFF(23), + UNDERLINE_OFF(24), + BLINK_OFF(25), + NEGATIVE_OFF(27), + CONCEAL_OFF(28), + STRIKETHROUGH_OFF(29); + + public int value; + + AnsiAttribute(int val) { + this.value = val; + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiColor.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiColor.java new file mode 100644 index 0000000..cc097d3 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/dal/pojo/meta/AnsiColor.java @@ -0,0 +1,35 @@ +package cd.casic.pipeline.dal.pojo.meta; + +public enum AnsiColor { + BLACK(0), + RED(1), + GREEN(2), + YELLOW(3), + BLUE(4), + MAGENTA(5), + CYAN(6), + WHITE(7), + DEFAULT(9); + + public int value; + + AnsiColor(int val) { + value = val; + } + + public int fg() { + return value + 30; + } + + public int bg() { + return value + 40; + } + + public int fgBright() { + return value + 90; + } + + public int bgBright() { + return value + 100; + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogErrorCodeEnum.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogErrorCodeEnum.java new file mode 100644 index 0000000..6063d79 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogErrorCodeEnum.java @@ -0,0 +1,20 @@ +package cd.casic.pipeline.enums; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; + +/** + * @author by mianbin + * @Classname LogErrorCodeEnum + * @Description 日志错误状态码枚举 + * @Date 2025/3/19 17:06 + */ +@Schema(title = "日志错误状态码") +@AllArgsConstructor +public enum LogErrorCodeEnum { + PRINT_QUEUE_LIMIT(2108005, "log print queue exceeds the limit"), + PRINT_IS_DISABLED(2108006, "log print config is disabled"); + + public int errorCode; + public String formatErrorMessage; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStatusEnum.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStatusEnum.java new file mode 100644 index 0000000..5bb57c7 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStatusEnum.java @@ -0,0 +1,52 @@ +package cd.casic.pipeline.enums; + +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.RequiredArgsConstructor; + +/** + * @author by mianbin + * @Classname LogStatus + * @Description 日志状态 + * @Date 2025/3/19 17:07 + */ +@RequiredArgsConstructor() +@Schema(title = "日志状态") +public enum LogStatusEnum { + @Schema(description = "查询成功") + SUCCEED(0), + @Schema(description = "日志为空") + EMPTY(1), + @Schema(description = "日志已过期") + CLEAN(2), + @Schema(description = "日志已清理") + CLOSED(3), + @Schema(description = "查询异常") + FAIL(999); + + public int status; + + LogStatusEnum(int status){ + this.status = status; + } + + @JsonValue + public int jsonValue() { + return status; + } + + public static LogStatusEnum parse(int status){ + switch (status){ + case 0: + return SUCCEED; + case 1: + return EMPTY; + case 2: + return CLEAN; + case 3: + return CLOSED; + default: + return FAIL; + } + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStorageMode.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStorageMode.java new file mode 100644 index 0000000..4de3566 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogStorageMode.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.enums; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @author by mianbin + * @Classname LogStorageMode + * @Description 日志保存模型 + * @Date 2025/3/19 17:10 + */ +@Schema(title = "日志保存模型") +public enum LogStorageMode { + @Schema(description = "上报服务") + UPLOAD, + @Schema(description = "本地保存") + LOCAL, + @Schema(description = "仓库已归档") + ARCHIVED; + + public static LogStorageMode parse(String modeName) { + if (modeName.equals(LOCAL.name())) { + return LOCAL; + } else if (modeName.equals(ARCHIVED.name())) { + return ARCHIVED; + } else { + return UPLOAD; + } + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogType.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogType.java new file mode 100644 index 0000000..7b112ae --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/enums/LogType.java @@ -0,0 +1,21 @@ +package cd.casic.pipeline.enums; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @author by mianbin + * @Classname LogType + * @Description 日志的类型 + * @Date 2025/3/19 17:12 + */ +@Schema(title = "日志的类型") +public enum LogType { + @Schema(description = "提醒日志") + WARN, + @Schema(description = "错误日志") + ERROR, + @Schema(description = "调试日志") + DEBUG, + @Schema(description = "普通的日志") + LOG +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/IEvent.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/IEvent.java new file mode 100644 index 0000000..6b81ffe --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/IEvent.java @@ -0,0 +1,12 @@ +package cd.casic.pipeline.event.log; + +import org.springframework.context.ApplicationEvent; + +/** + * @author by mianbin + * @Classname IEvent + * @Description 日志事件,现在暂时使用这种方式 + * @Date 2025/3/20 10:38 + */ +public abstract class IEvent { +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/ILogEvent.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/ILogEvent.java new file mode 100644 index 0000000..b4a2890 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/ILogEvent.java @@ -0,0 +1,26 @@ +package cd.casic.pipeline.event.log; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +/** + * @author by mianbin + * @Classname ILogEvent + * @Description TODO + * @Date 2025/3/20 10:45 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ILogEvent extends IEvent { + + protected String buildId; + protected int retryTime; + protected int delayMills; + protected static int DELAY_DURATION_MILLS = 3 * 1000; + + public int getNextDelayMills(int retryTime) { + return DELAY_DURATION_MILLS * (3 - retryTime); + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogOriginEvent.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogOriginEvent.java new file mode 100644 index 0000000..0632059 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogOriginEvent.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.event.log; + +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +import java.util.List; + +/** + * @author by mianbin + * @Classname LogOriginEvent + * @Description 目前不是广播事件,留着后面用mq时候会用到。 + * @Date 2025/3/20 10:47 + */ +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class LogOriginEvent extends ILogEvent { + private String buildId; + private List logs; + private int retryTime = 2; + private int delayMills = 0; + + public LogOriginEvent(String buildId, List logs) { + this.buildId = buildId; + this.logs = logs; + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStatusEvent.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStatusEvent.java new file mode 100644 index 0000000..9ddbaf7 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStatusEvent.java @@ -0,0 +1,24 @@ +package cd.casic.pipeline.event.log; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * @author by mianbin + * @Classname LogStatusEvent + * @Description 目前不是广播事件,留着后面用mq时候会用到。 + * @Date 2025/3/20 10:49 + */ +@Data +@AllArgsConstructor +public class LogStatusEvent extends ILogEvent{ + private String buildId; + private Boolean finished; + private String tag; + private String subTag; + private String jobId; + private int executeCount; + private int retryTime = 2; + private int delayMills = 0; +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStorageEvent.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStorageEvent.java new file mode 100644 index 0000000..065ecdb --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/event/log/LogStorageEvent.java @@ -0,0 +1,26 @@ +package cd.casic.pipeline.event.log; + +import cd.casic.pipeline.dal.pojo.message.LogMessageWithLineNo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * @author by mianbin + * @Classname LogStorageEvent + * @Description 目前不是广播事件,留着后面用mq时候会用到。 + * @Date 2025/3/20 10:50 + */ +@Data +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class LogStorageEvent extends ILogEvent { + + private String buildId; + private List logs; + private int retryTime = 2; + private int delayMills = 0; + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/CreateIndexBean.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/CreateIndexBean.java new file mode 100644 index 0000000..0b5ae7d --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/CreateIndexBean.java @@ -0,0 +1,55 @@ +package cd.casic.pipeline.jmx; + +import lombok.Synchronized; +import org.springframework.jmx.export.annotation.ManagedAttribute; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author by mianbin + * @Classname CreateIndexBean + * @Description TODO + * @Date 2025/3/20 10:25 + */ +@Component +@ManagedResource(objectName = "ops.ci.log.v2:type=index,operation=create", description = "log create index performance") +public class CreateIndexBean { + private AtomicLong executeCount = new AtomicLong(0); + private AtomicLong executeElapse = new AtomicLong(0); + private AtomicLong calculateCount = new AtomicLong(0); + private AtomicLong failureCount = new AtomicLong(0); + + @Synchronized + public void execute(long elapse, boolean success) { + executeCount.incrementAndGet(); + calculateCount.incrementAndGet(); + executeElapse.addAndGet(elapse); + if (!success) { + failureCount.incrementAndGet(); + } + } + + @Synchronized + @ManagedAttribute + public double getCreateIndexPerformance() { + long elapse = executeElapse.getAndSet(0); + long count = calculateCount.getAndSet(0); + if (count == 0L) { + return 0L; + } else { + return (double) elapse / count; + } + } + + @ManagedAttribute + public long getExecuteCount() { + return executeCount.get(); + } + + @ManagedAttribute + public long getFailureCount() { + return failureCount.get(); + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/LogStorageBean.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/LogStorageBean.java new file mode 100644 index 0000000..4efb7f9 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/jmx/LogStorageBean.java @@ -0,0 +1,55 @@ +package cd.casic.pipeline.jmx; + +import lombok.Synchronized; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author by mianbin + * @Classname LogStorageBean + * @Description * 日志保存模块,主要是使用原子类和 synchronized 关键字来保证并发性,记录每个操作的次数。 + * @Date 2025/3/20 10:26 + */ +@Component +@ManagedResource(objectName = "ops.ci.log.v2:type=logs", description = "log performance") +public class LogStorageBean { + + private AtomicLong batchWriteCount = new AtomicLong(0); + private AtomicLong batchWriteElapse = new AtomicLong(0); + private AtomicLong calculateCount = new AtomicLong(0); + private AtomicLong failureCount = new AtomicLong(0); + private AtomicLong bulkRequestCount = new AtomicLong(0); + private AtomicLong bulkRequestElapse = new AtomicLong(0); + private AtomicLong bulkRequestFailureCount = new AtomicLong(0); + private AtomicLong queryLogCount = new AtomicLong(0); + private AtomicLong queryLogElapse = new AtomicLong(0); + private AtomicLong queryCalculateCount = new AtomicLong(0); + private AtomicLong queryFailureCount = new AtomicLong(0); + private AtomicLong downloadLogCount = new AtomicLong(0); + private AtomicLong downloadLogElapse = new AtomicLong(0); + private AtomicLong downloadCalculateCount = new AtomicLong(0); + private AtomicLong downloadFailureCount = new AtomicLong(0); + + @Synchronized + public void query(Long elapse, boolean success) { + queryLogCount.incrementAndGet(); + queryCalculateCount.incrementAndGet(); + queryLogElapse.addAndGet(elapse); + if (!success) { + queryFailureCount.incrementAndGet(); + } + } + + @Synchronized + public void batchWrite(long elapse, boolean success) { + batchWriteCount.incrementAndGet(); + calculateCount.incrementAndGet(); + batchWriteElapse.addAndGet(elapse); + if (!success) { + failureCount.incrementAndGet(); + } + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogListenerService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogListenerService.java new file mode 100644 index 0000000..2b4e9d2 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogListenerService.java @@ -0,0 +1,99 @@ +package cd.casic.pipeline.service; + +import cd.casic.pipeline.event.log.LogOriginEvent; +import cd.casic.pipeline.event.log.LogStatusEvent; +import cd.casic.pipeline.event.log.LogStorageEvent; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.stereotype.Service; + +/** + * @author by mianbin + * @Classname BuildLogListenerService + * @Description TODO + * @Date 2025/3/20 15:30 + */ +@Slf4j +@Service +public class BuildLogListenerService { + @Resource + private LogService logService; + + @Resource + private IndexService indexService; + + @Resource + private BuildLogPrintService buildLogPrintService; + + public void handleEvent(LogOriginEvent event) { + boolean result = false; + try { + logService.addLogEvent(event); + result = true; + } catch (Throwable ignored) { + log.warn("Fail to add the log event" + event.getBuildId(), ignored); + } finally { + // 如果结果不对 + if (!result && event.getRetryTime() >= 0) { + log.warn("Retry to add the log event " + event.getBuildId() + "time left:" + event.getRetryTime()); +// buildLogPrintService.dispatchEvent( +// new LogOriginEvent( +// event.getBuildId(), +// event.getLogs(), +// // 获取下一次事件的间隔 +// event.getRetryTime() - 1, +// event.getNextDelayMills(event.getDelayMills()) +// ) +// ); + } + } + } + + // 处理日志储存事件 + public void handleEvent(LogStorageEvent event) { + boolean result = false; + try { + logService.addBatchLogEvent(event); + result = true; + } catch (Throwable ignored) { + log.warn("Fail to add the log batch event " + event.getBuildId(), ignored); + } finally { + // 如果结果不对,那就重试 + if (!result && event.getRetryTime() >= 0) { + log.warn("Retry to add the log batch event " + event.getBuildId() + "time left:" + event.getRetryTime()); +// buildLogPrintService.dispatchEvent( +// new LogStorageEvent( +// event.getBuildId(), +// event.getLogs(), +// // 获取下一次事件的间隔 +// event.getRetryTime() - 1, +// event.getNextDelayMills(event.getDelayMills()) +// ) +// ); + } + } + } + + // 处理日志状态事件 + public void handleEvent(LogStatusEvent event) { + boolean result = false; + try { + logService.updateLogStatus(event); + // #3089 当收到构建级别的状态刷新时,清理缓存并保存行数 + if (Strings.isBlank(event.getJobId()) && Strings.isBlank(event.getTag())) { + indexService.flushLineNum2DB(event.getBuildId()); + } + result = true; + } catch (Throwable ignored) { + log.warn("Fail to add the multi lines [" + event.getBuildId() + "|" + event.getRetryTime() + "]", ignored); + } finally { + // 如果结果不对,那就重试 + if (!result && event.getRetryTime() >= 0) { + log.warn("Retry to add the multi lines " + event.getBuildId() + "time left:" + event.getRetryTime()); + + } + } + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogPrintService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogPrintService.java new file mode 100644 index 0000000..0013ab0 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogPrintService.java @@ -0,0 +1,56 @@ +package cd.casic.pipeline.service; + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.framework.commons.util.spring.SpringUtils; +import cd.casic.pipeline.enums.LogErrorCodeEnum; +import cd.casic.pipeline.event.log.ILogEvent; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @author by mianbin + * @Classname BuildLogPrintService + * @Description 日志打印 + * @Date 2025/3/20 14:57 + */ +@Slf4j +@Service +public class BuildLogPrintService { + // todo, 这里线程池都是使用的默认参数,之后可以载入 logServiceConfig 在配置文件里面对参数进行修改 + private ThreadPoolExecutor logExecutorService = new ThreadPoolExecutor( + 100, + 100, + 0L, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(1000)); + + public void dispatchEvent(ILogEvent event) { + SpringUtils.publishEvent(event); + } + + // 异步打印日志 + public CommonResult asyncDispatchEvent(ILogEvent event) { + // todo 检测配置文件,如果没有开启日志保存,进行的一些处理 + try { + // 从线程池里面拿一个线程出来处理这个事件 + logExecutorService.execute(() -> { + System.out.println("BuildLogPrintService[ " + event.getBuildId() + "] " + event.toString()); +// dispatchEvent(event); + }); + return CommonResult.success(true); + } catch (RejectedExecutionException e) { + // 队列满时的处理逻辑 + log.error( + "BKSystemErrorMonitor | BuildLogPrintService[ " + event.getBuildId() + "] " + + "asyncDispatchEvent failed with queue tasks exceed the limit", e); + return CommonResult.error(509, LogErrorCodeEnum.PRINT_QUEUE_LIMIT.formatErrorMessage); + } + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogQueryService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogQueryService.java new file mode 100644 index 0000000..5f649ec --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/BuildLogQueryService.java @@ -0,0 +1,178 @@ +package cd.casic.pipeline.service; + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.dal.pojo.*; +import cd.casic.pipeline.enums.LogStatusEnum; +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.jmx.LogStorageBean; +import jakarta.annotation.Resource; +import org.springframework.http.ResponseEntity; + +/** + * @author by mianbin + * @Classname BuildLogQueryService + * @Description TODO + * @Date 2025/3/20 14:59 + */ +public class BuildLogQueryService { + + @Resource + private LogService logService; + @Resource + private LogStatusService logStatusService; + @Resource + private IndexService indexService; + @Resource + private LogStorageBean logStorageBean; + + public CommonResult getInitLogs(String userId, String projectId, String pipelineId, + String buildId, boolean debug, LogType logType, String tag, String jobId, int executeCount, String subTag) { + // todo 鉴权代码 + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW); + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + QueryLogs result = logService.queryInitLogs(buildId, debug, logType, tag, subTag, jobId, executeCount); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + QueryLogs queryLogs = result; + return CommonResult.success(queryLogs); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getInitLogsPage(String userId, String projectId, String pipelineId, + String buildId, boolean debug, LogType logType, String tag, String jobId, int executeCount, + int page, int pageSize, String subTag) { + // todo 鉴权代码 + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW); + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + PageQueryLogs result = logService.queryInitLogsPage(buildId, debug, logType, tag, subTag, jobId, executeCount,page,pageSize); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getMoreLogs(String userId, String projectId, String pipelineId, String buildId, boolean debug, + LogType logType, int num, boolean fromStart, long start, long end, String tag, String jobId, int executeCount,String subTag) { + // todo 鉴权代码 +// validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + QueryLogs result = logService.queryLogsBetweenLines(buildId,num,fromStart,start,end, debug, logType, tag, subTag, jobId, executeCount); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getAfterLogs(String userId, String projectId, String pipelineId, String buildId, + long start, boolean debug, LogType logType, String tag, String jobId, int executeCount,String subTag) { + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + QueryLogs result = logService.queryLogsAfterLine(buildId,start,debug,logType,tag, subTag, jobId, executeCount); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getBeforeLogs(String userId, String projectId, String pipelineId, String buildId, + long end, boolean debug, LogType logType, int size, String tag, String jobId, int executeCount, String subTag) { + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + QueryLogs result = logService.queryLogsBeforeLine(buildId,end,size,debug,logType,tag, subTag, jobId, executeCount); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getEndLogsPage(String userId, String projectId, String pipelineId, String buildId, + int size, boolean debug, LogType logType, String tag, String jobId, int executeCount, String subTag) { + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + EndPageQueryLogs result = logService.getEndLogsPage(pipelineId,buildId,debug,logType,tag, subTag, jobId, executeCount,size); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getBottomLogs(String userId, String projectId, String pipelineId, String buildId, + int size, boolean debug, LogType logType, String tag, String jobId, int executeCount, String subTag) { + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long startEpoch = System.currentTimeMillis(); + boolean success = false; + try { + QueryLogs result = logService.getBottomLogs(pipelineId,buildId,debug,logType,tag, subTag, jobId, executeCount,size); + // 设置查出来使用的时间 + result.setTimeUsed(System.currentTimeMillis() - startEpoch); + // 判断当前查出来的日志的状态 + success = logStatusSuccess(result.getStatus()); + return CommonResult.success(result); + } finally { + logStorageBean.query(System.currentTimeMillis() - startEpoch, success); + } + } + + public CommonResult getLogMode(String userId, String projectId, String pipelineId, String buildId, String tag, int executeCount) { + // 鉴权 + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + // 这里的 executeCount 默认为1 + return CommonResult.success(logStatusService.getStorageMode(buildId,tag,executeCount)); + } + + // 获取当前构建的最大行号 + public CommonResult getLastLineNum(String userId, String projectId, String pipelineId, String buildId) { + // validateAuth(userId, projectId, pipelineId, buildId, AuthPermission.VIEW) + long lastLineNum = indexService.getLastLineNum(buildId); + boolean finished = logStatusService.isFinish(buildId, null, null, null, 1); + QueryLogLineNum res = new QueryLogLineNum(buildId, finished, lastLineNum); + return CommonResult.success(res); + } + + private boolean logStatusSuccess(int logStatus) { + return LogStatusEnum.parse(logStatus) == LogStatusEnum.EMPTY || + LogStatusEnum.parse(logStatus) == LogStatusEnum.SUCCEED; + } + + public ResponseEntity downloadLogs(String userId, String projectId, String pipelineId, String buildId, + String tag, String jobId, int executeCount, String finaName, String subTag) { + return null; + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/IndexService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/IndexService.java new file mode 100644 index 0000000..7ed56bd --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/IndexService.java @@ -0,0 +1,180 @@ +package cd.casic.pipeline.service; + +import cd.casic.framework.redis.core.RedisTemplateUtils; +import cd.casic.pipeline.dal.dao.IndexMapper; +import cd.casic.pipeline.dal.dataobject.LogIndicesV2; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.redisson.RedissonRedLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +/** + * @author by mianbin + * @Classname IndexService + * @Description TODO + * @Date 2025/3/20 10:53 + */ +@Slf4j +@Service +public class IndexService { + + @Resource + private IndexMapper indexMapper; + + @Resource + private RedissonClient redissonClient; + + @Resource + private RedisTemplateUtils redisTemplateUtils; + + private static String LOG_INDEX_LOCK = "log:build:enable:lock:key"; + private static String LOG_LINE_NUM = "log:build:line:num:"; + private static String LOG_LINE_NUM_LOCK = "log:build:line:num:distribute:lock"; + private static Long INDEX_CACHE_MAX_SIZE = 100000L; + private static Long INDEX_CACHE_EXPIRE_MINUTES = 30L; + private static Long INDEX_LOCK_EXPIRE_SECONDS = 10L; + + // 返回 redis Key + public static String getLineNumRedisKey(String buildId) { + return LOG_LINE_NUM + buildId; + } + + // Caffeine 本地数据库,不存在数据时自动添加 + private LoadingCache indexCache = Caffeine.newBuilder() + .maximumSize(INDEX_CACHE_MAX_SIZE) + .expireAfterAccess(INDEX_CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES) + .build(key -> initialIndex(key)); + + // 如果不存在初始化 index 方法 + private String initialIndex(String buildId) { + String indexName = indexMapper.getIndexName(buildId); + + // 如果数据库里面都不存在 indexName,就使用分布式锁在数据库里面新增 + if (Strings.isBlank(indexName)){ + String lockKey = LOG_INDEX_LOCK + ":" + buildId; + RLock lock = redissonClient.getLock(lockKey); + RedissonRedLock redLock = new RedissonRedLock(lock); + try{ + redLock.lock(); + // 二次验证,防止重复 + indexName = indexMapper.getIndexName(buildId); + if (Strings.isBlank(indexName)){ + log.info(buildId + " Add the build record"); + indexName = saveIndex(buildId); + } + } finally { + lock.unlock(); + } + } + return indexName; + } + + // 保存index到 数据库 和 Redis 里面去,最后返回值保存在 Caffeine 里面 + private String saveIndex(String buildId) { + String indexName = indexMapper.getIndexName(buildId); + // 保存到 mongo + indexMapper.create(buildId,indexName,true); + // 保存到 redis + redisTemplateUtils.set(getLineNumRedisKey(buildId),"1",TimeUnit.DAYS.toSeconds(2)); + + log.info("["+buildId+"|"+indexName+"] Create new index in db and cache"); + + return indexName; + } + + public String getIndexName(String buildId) { + // 这里的 get 如果不存在就会初始化调用 initialIndex 方法 + String index = indexCache.get(buildId); + if (Strings.isBlank(index)) { + log.error("Fail to get the index of build from caffeine cache:" + buildId); + index = "testId"; + } + return index; + } + + public long getAndAddLineNum(String buildId, int size) { + // 获得并发锁 + RLock lock = redissonClient.getLock("$LOG_LINE_NUM_LOCK:$buildId"); + RedissonRedLock redissonRedLock = new RedissonRedLock(lock); + try { + redissonRedLock.lock(); + Object lineNum = redisTemplateUtils.get(getLineNumRedisKey(buildId)); + // 缓存命中则直接进行自增,缓存未命中则从db中取值,自增后再刷新缓存 + if (lineNum == null) { + log.warn("[" + buildId + "|[" + size + "] Fail to get and add the line num, get from db"); + // 从 indexMapper 里面取出 + LogIndicesV2 build = indexMapper.getBuild(buildId); + if (build == null) { + log.warn("[" + buildId + "|[" + size + "] The build is not exist in db"); + return -1; + } + log.warn("[" + buildId + "|" + size + "] Got from db, lastLineNum: " + build.getLastLineNum()); + lineNum = build.getLastLineNum() + size; + redisTemplateUtils.set(getLineNumRedisKey(buildId), lineNum, TimeUnit.DAYS.toSeconds(2)); + return build.getLastLineNum(); + } else { + lineNum = redisTemplateUtils.incr(getLineNumRedisKey(buildId), size); + } + return (long) lineNum - size; + } finally { + redissonRedLock.unlock(); + } + } + + public String getBuildIndexName(String buildId){ + LogIndicesV2 logIndices = indexMapper.getBuild(buildId); + if (logIndices == null) { + return ""; + } + return logIndices.getIndexName(); + } + + public long getLastLineNum(String buildId) { + Object number = redisTemplateUtils.get(getLineNumRedisKey(buildId)); + if (number != null) { + return (long) number; + } + log.error("Redis can't find the lineNumber"); + + // 如果为空就从数据库里面去取 + LogIndicesV2 build = indexMapper.getBuild(buildId); + if (build != null) { + return build.getLastLineNum(); + } + + // 如果还为空就返回0 + return 0; + } + + // 清理缓存并保存行数 + public void flushLineNum2DB(String buildId) { + String lineNum = (String) redisTemplateUtils.get(getLineNumRedisKey(buildId)); + if (Strings.isBlank(lineNum)) { + log.warn("[$buildId] Fail to get lineNum from redis"); + return; + } + // 看数据是否合法 + long latestLineNum = 0; + try { + latestLineNum = Long.parseLong(lineNum); + } catch (Exception e) { + log.warn("[" + buildId + "|" + lineNum + "] Fail to convert line num to long", e); + return; + } + // 如果更新成功 + if (indexMapper.updateLastLineNum(buildId, latestLineNum)) { + redisTemplateUtils.del(getLineNumRedisKey(buildId)); + } else { + log.warn("[" + buildId + "|" + latestLineNum + "] Fail to update the build latest line num"); + } + } + + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogService.java new file mode 100644 index 0000000..3179bab --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogService.java @@ -0,0 +1,109 @@ +package cd.casic.pipeline.service; + +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.event.log.LogOriginEvent; +import cd.casic.pipeline.event.log.LogStatusEvent; +import cd.casic.pipeline.event.log.LogStorageEvent; +import cd.casic.pipeline.dal.pojo.EndPageQueryLogs; +import cd.casic.pipeline.dal.pojo.PageQueryLogs; +import cd.casic.pipeline.dal.pojo.QueryLogs; + +/** + * @author by mianbin + * @Classname LogService + * @Description TODO + * @Date 2025/3/20 10:31 + */ +public interface LogService { + + QueryLogs queryInitLogs( + String buildId, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount + ); + + QueryLogs queryLogsBetweenLines( + String buildId, + int num, + boolean fromStart, + long start, + long end, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount + ); + + QueryLogs queryLogsAfterLine( + String buildId, + long start, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount + ); + + PageQueryLogs queryInitLogsPage( + String buildId, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount, + int page, + int pageSize + ); + + QueryLogs queryLogsBeforeLine( + String buildId, + long end, + int size, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount + ); + + EndPageQueryLogs getEndLogsPage( + String pipelineId, + String buildId, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount, + int size + ); + + QueryLogs getBottomLogs( + String pipelineId, + String buildId, + boolean debug, + LogType logType, + String tag, + String subTag, + String jobId, + int executeCount, + int size + ); + + + void addLogEvent(LogOriginEvent event); + + void addBatchLogEvent(LogStorageEvent event); + + void updateLogStatus(LogStatusEvent event); + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogServiceImpl.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogServiceImpl.java new file mode 100644 index 0000000..5b7a2de --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogServiceImpl.java @@ -0,0 +1,237 @@ +package cd.casic.pipeline.service; + +import cd.casic.pipeline.enums.LogType; +import cd.casic.pipeline.event.log.LogOriginEvent; +import cd.casic.pipeline.event.log.LogStatusEvent; +import cd.casic.pipeline.event.log.LogStorageEvent; +import cd.casic.pipeline.jmx.CreateIndexBean; +import cd.casic.pipeline.jmx.LogStorageBean; +import cd.casic.pipeline.dal.pojo.EndPageQueryLogs; +import cd.casic.pipeline.dal.pojo.PageQueryLogs; +import cd.casic.pipeline.dal.pojo.QueryLogs; +import cd.casic.pipeline.dal.pojo.message.LogMessage; +import cd.casic.pipeline.dal.pojo.message.LogMessageWithLineNo; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.redisson.RedissonRedLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author by mianbin + * @Classname LogServiceImpl + * @Description TODO + * @Date 2025/3/20 10:52 + */ +@Slf4j +@Service +public class LogServiceImpl implements LogService { + @Resource + private IndexService indexService; + @Resource + private LogStatusService logStatusService; + @Resource + private LogTagService logTagService; + @Resource + private CreateIndexBean createIndexBean; + @Resource + private LogStorageBean logStorageBean; + @Resource + private BuildLogPrintService buildLogPrintService; + @Resource + private RedissonClient redissonClient; + + private static long LONG_SEARCH_TIME = 64000; + private static long SHORT_SEARCH_TIME = 32000; + private static long SEARCH_TIMEOUT_SECONDS = 60L; + private static long SEARCH_FRAGMENT_SIZE = 100000; + private static long INDEX_CACHE_MAX_SIZE = 100000L; + private static long INDEX_CACHE_EXPIRE_MINUTES = 30L; + private static long INDEX_LOCK_EXPIRE_SECONDS = 10L; + private static long INDEX_STORAGE_WARN_MILLIS = 1000; + private Cache indexCache = Caffeine.newBuilder() + .maximumSize(INDEX_CACHE_MAX_SIZE).expireAfterAccess(INDEX_CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES) + .build(); + + @Override + public void addLogEvent(LogOriginEvent event) { +// List logMessage = addLineNo(event.getBuildId(),event.getLogs()); + +// if (!logMessage.isEmpty()) { +// buildLogPrintService.dispatchEvent(new LogStorageEvent(event.getBuildId(), logMessage)); +// } + } + + @Override + public void addBatchLogEvent(LogStorageEvent event) { + long currentEpoch = System.currentTimeMillis(); + boolean success = false; + try { + // todo 提前准备索引 + prepareIndex(event.getBuildId()); + List logMessages = event.getLogs(); + List buf = new ArrayList<>(); + // 遍历日志信息 + for (LogMessageWithLineNo logMessage : logMessages) { + buf.add(logMessage); +// if (buf.size() == Constants.BULK_BUFFER_SIZE){ +// // 添加多行日志 +// if (doAddMultiLines(buf,event.getBuildId()) == 0){ +// throw new Exception( +// "None of lines is inserted successfully to ES " + +// "["+event.getBuildId()+"|"+event.getRetryTime()+"}]" +// ); +// } else { +// buf.clear(); +// } +// } + } + if (!buf.isEmpty()) { + if (doAddMultiLines(buf, event.getBuildId()) == 0) { + throw new Exception("None of lines is inserted successfully to ES" + "[" + event.getBuildId() + "|" + event.getRetryTime() + "}]"); + } + } + success = true; + } catch (Exception e) { + e.printStackTrace(); + } finally { + long elapse = System.currentTimeMillis() - currentEpoch; + logStorageBean.batchWrite(elapse, success); + + // #4265 当日志消息处理时间过长时打印消息内容 + if (elapse >= INDEX_STORAGE_WARN_MILLIS && !event.getLogs().isEmpty()) { + log.warn("[" + event.getBuildId() + "] addBatchLogEvent spent too much time(" + elapse + ") with tag=" + event.getLogs().get(0).getTag() + "}"); + } + } + } + + private int doAddMultiLines(List buf, String buildId) { + return 0; + } + + // todo 在ES里面创建index + private void createIndex(String buildId, String index) { + + } + + // todo 给ES数据库存消息 + private boolean isExistIndex(String buildId, String index) { + return true; + } + + @Override + public QueryLogs queryInitLogs(String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return doQueryInitLogs(buildId, debug, logType, tag, subTag, jobId, executeCount); + } + + private QueryLogs doQueryInitLogs(String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + // todo 从 ES 数据库里面取出数据 + return null; + } + + @Override + public QueryLogs queryLogsBetweenLines(String buildId, int num, boolean fromStart, long start, long end, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return null; + } + + @Override + public QueryLogs queryLogsAfterLine(String buildId, long start, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return null; + } + + @Override + public PageQueryLogs queryInitLogsPage(String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount, int page, int pageSize) { + return null; + } + + @Override + public QueryLogs queryLogsBeforeLine(String buildId, long end, int size, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount) { + return null; + } + + @Override + public EndPageQueryLogs getEndLogsPage(String pipelineId, String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount, int size) { + return null; + } + + @Override + public QueryLogs getBottomLogs(String pipelineId, String buildId, boolean debug, LogType logType, String tag, String subTag, String jobId, int executeCount, int size) { + return null; + } + + @Override + public void updateLogStatus(LogStatusEvent event) { +// logStatusService.finish(event.getBuildId(),event.getTag(),event.getSubTag(), +// event.getJobId(),event.getExecuteCount(),event.getLogStorageMode(),event.getFinished()); + } + + private List addLineNo(String buildId, List logMessages) { + long lineNum = indexService.getAndAddLineNum(buildId, logMessages.size()); + + if (lineNum == -1) { + log.error("Got null logIndex from indexService, buildId: " + buildId); + return new ArrayList<>(); + } + // 不为空的话 + long startLineNum = lineNum; + List res = new ArrayList<>(); + // 遍历 logMessages + for (LogMessage logMessage : logMessages) { + // 设置 timestamp + long timestamp = logMessage.getTimestamp(); + if (timestamp == 0L) { + timestamp = System.currentTimeMillis(); + } + // 如果 tag 不为空 + if (!StringUtils.isEmpty((logMessage.getSubTag()))) { + logTagService.saveSubTag(buildId, logMessage.getTag(), logMessage.getSubTag()); + } + res.add(new LogMessageWithLineNo(logMessage.getTag(), logMessage.getSubTag(), + logMessage.getJobId(), logMessage.getMessage(), + timestamp, logMessage.getLogType(), startLineNum++, logMessage.getExecuteCount()) + ); + } + return res; + } + + private boolean prepareIndex(String buildId) { + String index = indexService.getIndexName(buildId); + if (!checkIndexCreate(buildId, index)) { + createIndex(buildId, index); + indexCache.put(index, true); + return true; + } + return true; + } + + private boolean checkIndexCreate(String buildId, String index) { + if (indexCache.getIfPresent(index) == true) { + return true; + } + RLock lock = redissonClient.getLock("LOG:index:create:lock:key:$index"); + RedissonRedLock redissonRedLock = new RedissonRedLock(lock); + try { + redissonRedLock.lock(); + if (indexCache.getIfPresent(index) == true) { + return true; + } + // Check from ES + if (isExistIndex(buildId, index)) { + log.info("[" + buildId + "|" + index + "] the index is already created"); + indexCache.put(index, true); + return true; + } + return false; + } finally { + redissonRedLock.unlock(); + } + } +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogStatusService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogStatusService.java new file mode 100644 index 0000000..032cbe8 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogStatusService.java @@ -0,0 +1,90 @@ +package cd.casic.pipeline.service; + +import cd.casic.pipeline.dal.dao.LogStatusMapper; +import cd.casic.pipeline.enums.LogStorageMode; +import cd.casic.pipeline.dal.pojo.QueryLogStatus; +import cd.casic.pipeline.dal.pojo.TaskBuildLogProperty; +import cd.casic.pipeline.dal.dataobject.LogStatus; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author by mianbin + * @Classname LogStatusService + * @Date 2025/3/20 14:27 + */ +@Slf4j +@Service +public class LogStatusService { + + @Resource + private LogStatusMapper logStatusMapper; + + public void finish(String buildId, String tag, String subTag, String jobId, int executeCount, LogStorageMode logStorageMode, Boolean finished) { + // todo 当死锁的时候重试 + LogStatus logStatus = new LogStatus(buildId, tag, subTag, jobId, logStorageMode.name(), executeCount, finished); + logStatusMapper.insert(logStatus); + } + + public void updateStorageMode(String buildId, int executeCount, List propertyList) { + // 开始循环更新 + for (TaskBuildLogProperty property : propertyList) { + // 先弄出更新的mode + // 写出更新的后置 where 条件,buildId 和 elementId 和 executeCount 相等 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(LogStatus::getBuildId, buildId) + .eq(LogStatus::getTag, property.getElementId()) + .eq(LogStatus::getExecuteCount, executeCount); + LogStatus logStatus = logStatusMapper.selectOne(wrapper); + logStatus.setMode(property.getLogStorageMode().name()); + logStatusMapper.update(logStatus, wrapper); + } + } + + public QueryLogStatus getStorageMode(String buildId, String tag, int executeCount) { + // 获取 record + LogStatus record = logStatusMapper.selectOne(Wrappers.lambdaQuery() + .eq(LogStatus::getBuildId, buildId) + .eq(LogStatus::getTag, tag) + .eq(LogStatus::getExecuteCount, executeCount)); + + if (record != null) { + return new QueryLogStatus(buildId, record.getFinished(), LogStorageMode.parse(record.getMode())); + } else { + return new QueryLogStatus(buildId, false, LogStorageMode.UPLOAD); + } + } + + public boolean isFinish(String buildId, String tag, String subTag, String jobId, int executeCount) { + // 判空 + if (tag == null) + tag = ""; + if (subTag == null) + subTag = ""; + // #8804 将db中保存字段兜底为空字符串,方便唯一键冲突判断,也就是 jobId + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() + .eq(LogStatus::getBuildId, buildId) + .eq(LogStatus::getExecuteCount, executeCount); + if (!Strings.isBlank(jobId)) { + queryWrapper.eq(LogStatus::getJobId, jobId) + .eq(LogStatus::getTag, "") + .eq(LogStatus::getSubTag, ""); + } else { + queryWrapper + .eq(LogStatus::getTag, tag) + .eq(LogStatus::getSubTag, subTag); + } + LogStatus res = logStatusMapper.selectOne(queryWrapper); + if (res != null) { + return res.getFinished(); + } + return false; + } + +} diff --git a/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogTagService.java b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogTagService.java new file mode 100644 index 0000000..7793d18 --- /dev/null +++ b/modules/pipeline-ci-log/src/main/java/cd/casic/pipeline/service/LogTagService.java @@ -0,0 +1,102 @@ +package cd.casic.pipeline.service; + +import cd.casic.framework.commons.util.json.JsonUtils; +import cd.casic.framework.redis.core.RedisTemplateUtils; +import cd.casic.pipeline.dal.dao.LogTahMapper; +import com.fasterxml.jackson.core.type.TypeReference; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.redisson.RedissonRedLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author by mianbin + * @Classname LogTagService + * @Description TODO + * @Date 2025/3/20 14:49 + */ +@Slf4j +@Service +public class LogTagService { + + @Resource + private LogTahMapper logTahMapper; + @Resource + private RedisTemplateUtils redisTemplateUtils; + @Resource + private RedissonClient redissonClient; + + private static String LOG_SUBTAG = "log:build:tag:subTags:"; + private static String LOG_SUBTAG_LOCK = "log:build:tag:subTags:distribute:lock:"; + + public static String getSubTagsRedisKey(String buildId, String tagName) { + return LOG_SUBTAG + genBuildIdAndTagKey(buildId, tagName); + } + + private static String genBuildIdAndTagKey(String buildId, String tagName) { + return buildId + ":" + tagName; + } + + public void saveSubTag(String buildId, String tagName, String subTag) { + // 从 redis 和数据库里面 看是否已经保存 + List originSubTags = getSubTags(buildId, tagName); + // 如果已经保存了 + if (originSubTags != null && originSubTags.contains(subTag)) { + return; + } + + // 如果没有保存,也就是数据库里面没有 + List subTags = new ArrayList<>(); + subTags.add(subTag); + + if (originSubTags != null) { + subTags.addAll(originSubTags); + } + + // 存入数据库 + logTahMapper.save(buildId, tagName, JsonUtils.toJsonString(subTags)); + saveSubTagsToRedis(buildId, tagName, JsonUtils.toJsonString(subTags)); + + log.info("[" + buildId + "|" + tagName + "] Create new subTag in db and redis: " + subTag); + } + + private List getSubTags(String buildId, String tagName) { + // 看 redis 里面有没有 + String subTagsStr = (String) redisTemplateUtils.get(getSubTagsRedisKey(buildId, tagName)); + + if (Strings.isBlank(subTagsStr)) { + // redis 里面没有就看数据库里面有木有 + String subTags = logTahMapper.getSubTags(buildId, tagName); + if (subTags != null) { + // 如果有,就存入 redis 并且返回 + saveSubTagsToRedis(buildId, tagName, subTags); + return JsonUtils.parseObject(subTags, new TypeReference>() { + }); + } + // 没有返回 null + return null; + } else { + return JsonUtils.parseObject(subTagsStr, new TypeReference>() { + }); + } + } + + private void saveSubTagsToRedis(String buildId, String tagName, String subTags) { + RLock lock = redissonClient.getLock(LOG_SUBTAG_LOCK); + RedissonRedLock redisLock = new RedissonRedLock(lock); + try { + redisLock.lock(); + redisTemplateUtils.set(getSubTagsRedisKey(buildId, tagName), subTags, TimeUnit.DAYS.toSeconds(1)); + } finally { + redisLock.unlock(); + } + } + +} diff --git a/modules/pipeline-ci-market/pom.xml b/modules/pipeline-ci-market/pom.xml new file mode 100644 index 0000000..7dc6d65 --- /dev/null +++ b/modules/pipeline-ci-market/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-market + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-market/src/main/java/cd/casic/pipeline/market/constant/StoreMessageCode.java b/modules/pipeline-ci-market/src/main/java/cd/casic/pipeline/market/constant/StoreMessageCode.java new file mode 100644 index 0000000..351562b --- /dev/null +++ b/modules/pipeline-ci-market/src/main/java/cd/casic/pipeline/market/constant/StoreMessageCode.java @@ -0,0 +1,135 @@ +package cd.casic.pipeline.market.constant; + +/** + * 流水线微服务模块请求返回状态码 + * 返回码制定规则(0代表成功,为了兼容历史接口的成功状态都是返回0): + * 1、返回码总长度为7位, + * 2、前2位数字代表系统名称(如21代表持续集成平台) + * 3、第3位和第4位数字代表微服务模块(00:common-公共模块 01:process-流水线 02:artifactory-版本仓库 03:dispatch-分发 04:dockerhost-docker机器 + * 05:environment-环境 06:experience-版本体验 07:image-镜像 08:log-日志 09:measure-度量 10:monitoring-监控 11:notify-通知 + * 12:openapi-开放api接口 13:plugin-插件 14:quality-质量红线 15:repository-代码库 16:scm-软件配置管理 17:support-支撑服务 + * 18:ticket-证书凭据 19:project-项目管理 20:store-商店 21: auth-权限 22:sign-签名服务 23:metrics-度量服务 24:external-外部 + * 25:prebuild-预建 26: dispatcher-kubernetes 27:buildless 28: lambda 29: stream 30: worker 31: dispatcher-docker + * 32: remotedev 35:misc-杂项) + * 4、最后3位数字代表具体微服务模块下返回给客户端的业务逻辑含义(如001代表系统服务繁忙,建议一个模块一类的返回码按照一定的规则制定) + * 5、系统公共的返回码写在CommonMessageCode这个类里面,具体微服务模块的返回码写在相应模块的常量类里面 + * + * @author by mianbin + * @Classname StoreMessageCode + */ +public class StoreMessageCode { + public static final String MSG_CODE_BUILD_TYPE_PREFIX = "buildType.";// 构建资源类型国际化前缀 + public static final String USER_QUERY_ATOM_PERMISSION_IS_INVALID = "2120001";// 研发商店:没有插件的查看权限 + public static final String USER_QUERY_PROJECT_PERMISSION_IS_INVALID = "2120002";// 研发商店:没有项目的查看权限 + public static final String USER_CREATE_REPOSITORY_FAIL = "2120003";// 研发商店:创建代码库失败,请稍后再试 + public static final String USER_INSTALL_ATOM_CODE_IS_INVALID = "2120004";// 研发商店:安装插件失败 + public static final String USER_REPOSITORY_PULL_TASK_JSON_FILE_FAIL = "2120005";// 研发商店:从[{0}]分支拉取插件配置文件[task.json]失败,请确认是否OAUTH授权、文件是否正确上传代码库等 + public static final String USER_REPOSITORY_TASK_JSON_FIELD_IS_NULL = "2120006";// 研发商店:插件配置文件[task.json]{0}字段不能为空 + public static final String USER_REPOSITORY_TASK_JSON_FIELD_IS_NOT_MATCH = "2120007";// 研发商店:插件配置文件[task.json]{0}字段与工作台录入的不一致 + public static final String USER_ATOM_RELEASE_STEPS_ERROR = "2120008";// 研发商店:插件发布流程状态变更顺序不正确 + public static final String USER_ATOM_VERSION_IS_NOT_FINISH = "2120009";// 研发商店:插件{0}的{1}版本发布未结束,请稍后再试 + public static final String USER_ATOM_VERSION_IS_INVALID = "2120010";// 研发商店:插件升级的版本号{0}错误,应为{1} + public static final String USER_LOGO_SIZE_IS_INVALID = "2120011";// logo的尺寸应为{0}x{1} + public static final String USER_LOGO_TYPE_IS_NOT_SUPPORT = "2120012";// logo不支持{0}类型,可以上传{1}类型 + public static final String UPLOAD_LOGO_IS_TOO_LARGE = "2120013";// 研发商店:上传的logo文件不能超过{0} + public static final String USER_ATOM_CONF_INVALID = "2120014";// 研发商店:插件配置文件{0}格式不正确,错误原因:{1} + public static final String USER_ATOM_VISIBLE_DEPT_IS_INVALID = "2120015";// 研发商店:你不在{0}插件的可见范围之内,请联系插件发布者 + public static final String USER_COMPONENT_ADMIN_COUNT_ERROR = "2120016";// 研发商店:管理员个数不能少于1个 + public static final String ADD_ATOM_PLATFORM_INFO_FAILED = "2120017";// 添加插件对接平台信息失败 + public static final String USER_ATOM_QUALITY_CONF_INVALID = "2120018";// 研发商店:插件配置文件[quality.json]{0}格式不正确,请检查 + public static final String USER_REPOSITORY_PULL_QUALITY_JSON_FILE_FAIL = "2120019";// 研发商店:从[{0}]分支拉取插件配置文件[quality.json]失败,请确认是否OAUTH授权、文件是否正确上传代码库等 + public static final String USER_ATOM_USED = "2120020";// 研发商店:插件{0}已被项目{1}下的流水线使用,不可以卸载 + public static final String USER_ATOM_UNINSTALL_REASON_USED = "2120021";// 研发商店:插件卸载原因{0}已被使用,不能删除。建议禁用 + public static final String USER_COMPONENT_RELEASED_IS_NOT_ALLOW_DELETE = "2120022";// 研发商店:组件{0}已发布到商店,请先下架再删除 + public static final String USER_ATOM_USED_IS_NOT_ALLOW_DELETE = "2120023";// 研发商店:插件{0}已安装到其他项目下使用,请勿移除 + public static final String USER_REPOSITORY_BK_FRONTEND_DIR_IS_NULL = "2120024";// 研发商店:插件代码库文件夹[{0}]未创建 + public static final String USER_ATOM_IS_NOT_ALLOW_USE_IN_PROJECT = "2120025";// 你的项目[{0}]不允许使用插件[{1}],请检查插件是否被正确安装 + public static final String USER_REPOSITORY_TASK_JSON_FIELD_IS_INVALID = "2120026";// 研发商店:插件配置文件[task.json]{0}格式不正确,请检查 + public static final String USER_ATOM_IS_NOT_ALLOW_REPLACE = "2120027";// 研发商店:插件[{0}]的[{1}]版本无法被插件[{2}]的[{3}]版本替换,插件[{2}]的{4}参数无法映射替换 + public static final String USER_TO_ATOM_IS_NOT_BE_HIS_ATOM = "2120028";// 研发商店:目标替换插件不能是历史内置老插件 + public static final String USER_ATOM_NOT_COMPATIBLE_INPUT_FIELD = "2120029";// 研发商店:插件当前版本新增了无默认值的必填入参[{0}],将导致存量流水线执行异常,请修改发布类型进行非兼容式升级 + public static final String USER_ATOM_COMPATIBLE_INPUT_FIELD_CONFIRM = "2120030";// 研发商店:插件当前版本新增了入参[{0}],请确认插件执行逻辑对这些参数不存在或值为空的情况做了兼容处理,否则有可能导致存量流水线执行异常 + public static final String USER_ATOM_COMPATIBLE_OUTPUT_FIELD_CONFIRM = "2120031";// 研发商店:插件当前版本减少了出参[{0}],请确认插件执行逻辑对这些参数不存在或值为空的情况做了兼容处理,否则有可能导致存量流水线执行异常 + public static final String USER_ATOM_INPUT_NUM_IS_TOO_MANY = "2120032";// 研发商店:插件入参数量太多,系统规定的数量最大为:{0} + public static final String USER_ATOM_OUTPUT_NUM_IS_TOO_MANY = "2120033";// 研发商店:插件出参数量太多,系统规定的数量最大为:{0} + public static final String USER_REPOSITORY_TASK_JSON_OS_DEFAULT_ENV_IS_INVALID = "2120034";// 研发商店:配置文件[{0}]{1}操作系统默认环境配置数量为{2}个,默认环境配置数量有且只能为1个 + public static final String USER_REPOSITORY_PULL_ERROR_JSON_FILE_FAIL = "2120035";// 研发商店:从[{0}]分支拉取插件配置文件[error.json]失败,请确认是否OAUTH授权、文件是否正确上传代码库等 + public static final String USER_REPOSITORY_ERROR_JSON_ERROR_CODE_EXIST_DUPLICATE = "2120036";// 研发商店:插件配置文件[error.json]errorCode字段数据重复,请检查{0} + public static final String USER_REPOSITORY_ERROR_JSON_FIELD_IS_INVALID = "2120037";// 研发商店:插件配置文件[error.json]errorCode格式不正确,请检查 + public static final String TASK_JSON_CONFIGURE_FORMAT_ERROR = "2120038";// 参数[{0}] 的{1} ,请检查task.json配置格式是否正确 \n + public static final String GET_ATOM_LANGUAGE_ENV_INFO_FAILED = "2120039";// 获取插件开发语言相关的环境变量信息失败 + ;// 研发商店:插件配置文件[task.json]config配置格式不正确,{0} + public static final String TASK_JSON_CONFIG_IS_INVALID = "2120040";// 研发商店: 拉取文件[{0}]失败,失败原因:{1} + public static final String USER_PULL_FILE_FAIL = "2120041";// 插件包文件[{0}]不存在,请检查文件所在路径是否正确 + public static final String ATOM_PACKAGE_FILE_NOT_FOUND = "2120042"; + public static final String USER_TEMPLATE_VERSION_IS_NOT_FINISH = "2120201";// 研发商店:模板{0}的{1}版本发布未结束,请稍后再试 + public static final String USER_TEMPLATE_RELEASE_STEPS_ERROR = "2120202";// 研发商店:模板发布流程状态变更顺序不正确 + public static final String USER_TEMPLATE_ATOM_VISIBLE_DEPT_IS_INVALID = "2120203";// 研发商店:模板的可见范围不在插件{0}的可见范围之内,如有需要请联系插件的发布者 + public static final String USER_TEMPLATE_ATOM_NOT_INSTALLED = "2120204";// 研发商店:模版下的插件{0}尚未安装,请先安装后再使用 + public static final String USER_TEMPLATE_RELEASED = "2120205";// 研发商店:模版{0}已发布到商店,请先下架再删除 + public static final String USER_TEMPLATE_USED = "2120206";// 研发商店:模版{0}已安装到其他项目下使用,请勿移除 + public static final String USER_TEMPLATE_ATOM_IS_INVALID = "2120207";// 研发商店:模版下的插件{0}不可用,请联系模板发布者 + public static final String USER_TEMPLATE_IMAGE_VISIBLE_DEPT_IS_INVALID = "2120208";// 研发商店:模板的可见范围不在镜像[{0}]的可见范围之内,如有需要请联系镜像的发布者 + public static final String USER_TEMPLATE_IMAGE_IS_INVALID = "2120209";// 研发商店:模版下的镜像{0}不可用,请联系模板发布者 + public static final String USER_INSTALL_TEMPLATE_CODE_IS_INVALID = "2120210";// 研发商店: 商店模板{0}安装到项目[{1}]失败,模板已安装或项目下存在与模板{0}同名的自定义模板,若有同名的自定义模板请修改模板名称后再安装商店模版。 + public static final String USER_IMAGE_VERSION_IS_NOT_FINISH = "2120301";// 研发商店:镜像{0}的{1}版本发布未结束,请稍后再试 + public static final String USER_IMAGE_VERSION_IS_INVALID = "2120302";// 研发商店:镜像升级的版本号{0}错误,应为{1} + public static final String USER_IMAGE_RELEASE_STEPS_ERROR = "2120303";// 研发商店:镜像发布流程中状态变更顺序不正确 + public static final String USER_IMAGE_RELEASED = "2120304";// 研发商店:镜像{0}已发布到商店,请先下架再删除 + public static final String USER_IMAGE_USED = "2120305";// 研发商店:镜像{0}已安装到其他项目下使用,请勿移除 + public static final String USER_IMAGE_NOT_INSTALLED = "2120306";// 研发商店:项目{0}未安装镜像{1},无法使用 + public static final String USER_IMAGE_UNKNOWN_SOURCE_TYPE = "2120307";// 研发商店:镜像原始来源类型未知:{0} + public static final String USER_IMAGE_UNKNOWN_IMAGE_CATEGORY = "2120308";// 镜像范畴未知:{0} + public static final String USER_IMAGE_NOT_EXIST = "2120309";// 镜像[{0}]不存在 + public static final String USER_IMAGE_VERSION_NOT_EXIST = "2120310";// 标识为{0}版本号为{1}的镜像不存在 + public static final String USER_IMAGE_PROJECT_IS_INVALID = "2120311";// 研发商店:容器镜像[{0}]在项目[{1}]下不可用,请联系镜像发布者调整可见范围,调整后手动安装镜像 + public static final String USER_SERVICE_RELEASED_IS_NOT_ALLOW_DELETE = "2120401";// 研发商店:扩展服务{0}已发布到商店,请先下架再删除 + public static final String USER_SERVICE_USED_IS_NOT_ALLOW_DELETE = "2120402";// 研发商店:扩展服务{0}已安装到其他项目下使用,请勿移除 + public static final String USER_SERVICE_VERSION_IS_INVALID = "2120403";// 研发商店:扩展服务升级的版本号{0}错误,应为{1} + public static final String USER_SERVICE_VERSION_IS_NOT_FINISH = "2120404";// 研发商店:扩展服务{0}的{1}版本发布未结束,请稍后再试 + public static final String USER_SERVICE_CODE_DIFF = "2120405";// 研发商店:扩展编码与extension.json文件内编码不一致 + public static final String USER_SERVICE_RELEASE_STEPS_ERROR = "2120406";// 研发商店:扩展服务发布流程状态变更顺序不正确 + public static final String USER_SERVICE_PROJECT_UNENABLE = "2120407";// 研发商店:选中调试项目已被禁用 + public static final String USER_SERVICE_PROJECT_NOT_PERMISSION = "2120408";// 研发商店:选中调试项目无创建流水线权限 + public static final String USER_SERVICE_NOT_EXIST = "2120409";// 研发商店:扩展服务不存在{0} + public static final String USER_ITEM_SERVICE_USED_IS_NOT_ALLOW_DELETE = "2120410";// 研发商店:扩展点下还有可用的扩展服务,不能删除 + public static final String USER_SERVICE_NOT_DEPLOY = "2120411";// 研发商店:用户扩展服务未部署 + public static final String USER_PRAISE_IS_INVALID = "2120901";// 研发商店:你已点赞过 + public static final String USER_PROJECT_IS_NOT_ALLOW_INSTALL = "2120902";// 研发商店:你没有权限将组件安装到项目:{0} + public static final String USER_COMMENT_IS_INVALID = "2120903";// 研发商店:你已评论过,无法继续添加评论。但可以修改原有评论 + public static final String USER_CLASSIFY_IS_NOT_ALLOW_DELETE = "2120904";// 研发商店:该分类下还有正在使用的组件,不允许直接删除 + public static final String USER_APPROVAL_IS_NOT_ALLOW_REPEAT_APPLY = "2120905";// 研发商店:你已有处于待审批或审批通过的申请单,请勿重复申请 + public static final String USER_UPLOAD_PACKAGE_INVALID = "2120906";// 研发商店:请确认上传的包是否正确 + public static final String USER_SENSITIVE_CONF_EXIST = "2120907";// 研发商店:字段名{0}已存在 + public static final String USER_START_CODECC_TASK_FAIL = "2120908";// 研发商店:启动代码扫描任务失败 + public static final String USER_CHANGE_TEST_PROJECT_FAIL = "2120909";// 研发商店:用户[{0}]没有项目[{1}]下的流水线新增/修改/执行权限,请先给用户赋权 + public static final String SENSITIVE_API_PASSED_IS_NOT_ALLOW_CANCEL = "2120910";// 研发商店:敏感API已经审批通过不能取消 + public static final String SENSITIVE_API_APPROVED_IS_NOT_ALLOW_PASS = "2120911";// 研发商店:敏感API已经取消不能审批 + public static final String SENSITIVE_API_NOT_EXIST = "2120912";// 研发商店:敏感API[{0}]不存在 + public static final String USER_HIS_VERSION_UPGRADE_INVALID = "2120913";// 研发商店:当前发布类型下仅能新增历史大版本下的小版本,请修改版本号或者发布类型 + public static final String USER_UPLOAD_FILE_PATH_ERROR = "2120914";// 研发商店:文件路径[{0}]错误 + public static final String USER_ERROR_CODE_INVALID = "2120915";// 研发商店:错误码{0}格式错误 + public static final String USER_LOCALE_FILE_NOT_EXIST = "2120916";// 研发商店:未提供系统[{0}]语言的配置文件 + public static final String NO_COMPONENT_ADMIN_PERMISSION = "2120917";// 无组件{0}管理员权限,请联系组件管理员。 + public static final String GET_INFO_NO_PERMISSION = "2120918";// 无权限访问组件{0}信息,请联系组件管理员获取权限 + public static final String PROJECT_NO_PERMISSION = "2120919";// 无权限,非项目{0}成员或非插件{1}安装人 + public static final String IMAGE_ADD_NO_PROJECT_MEMBER = "2120920";// 无权限新增镜像,不是项目{0}成员 + public static final String IMAGE_PUBLISH_REPO_NO_PERMISSION = "2120921";// 无权限操作公共镜像仓库 + public static final String COMMENT_UPDATE_NO_PERMISSION = "2120922";// 不是该评论的发表人,无权限更新该评论 + public static final String BUILD_VISIT_NO_PERMISSION = "2120923";// 接口请求中的插件【{0}】不是当前当前构建运行的插件 + public static final String VERSION_PUBLISHED = "2120924";// 组件{0}版本({1})已发布 + public static final String NO_COMPONENT_ADMIN_AND_CREATETOR_PERMISSION = "2120925";// 无组件{0}管理员或当前版本创建者权限,请联系组件管理员。 + public static final String USER_NOT_IS_STORE_MEMBER = "2120926";// 研发商店:用户{0}不是组件成员 + public static final String GET_BRANCH_COMMIT_INFO_ERROR = "2120927";// 获取分支提交信息异常 + public static final String STORE_BRANCH_NO_NEW_COMMIT = "2120928";// 代码未变更,分支测试版本生成失败 + public static final String STORE_VERSION_IS_NOT_FINISH = "2120929";// 研发商店:组件[{0}]的[{1}]版本发布未结束,请稍后再试 + public static final String STORE_RELEASE_STEPS_ERROR = "2120930";// 研发商店:组件发布流程中状态变更顺序不正确 + public static final String STORE_PROJECT_COMPONENT_NO_PERMISSION = "2120931";// 研发商店:项目[{0}]没有组件[{1}]的使用权限,请先安装组件 + public static final String STORE_VERSION_IS_INVALID = "2120932";// 研发商店:组件升级的版本号{0}错误,请参照版本号升级规范填入正确版本号 + public static final String STORE_INSTALL_VALIDATE_FAIL = "2120933";// 研发商店: 组件{0}安装校验失败,失败原因:{1} + public static final String STORE_COMPONENT_REPO_FILE_DELETE_FAIL = "2120934";// 研发商店:组件仓库文件删除失败 + ;// 当 queryProjectComponentFlag、installed 或 updateFlag 参数不为空时, projectCode 参数必须非空 + public static final String STORE_QUERY_PARAM_CHECK_FAIL = "2120935"; + public static final String STORE_COMPONENT_IS_NOT_ALLOW_OFFLINE = "2120936";// 研发商店:非发布状态的版本不允许下架 + public static final String STORE_COMPONENT_CODE_REPOSITORY_DELETE_FAIL = "2120937";// 研发商店:代码库删除失败,失败原因:{0} +} diff --git a/modules/pipeline-ci-process/pom.xml b/modules/pipeline-ci-process/pom.xml new file mode 100644 index 0000000..493957a --- /dev/null +++ b/modules/pipeline-ci-process/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-process + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + + cd.casic.pipeline + pipeline-ci-event + + + + cd.casic.pipeline + pipeline-ci-log + + + + cd.casic.pipeline + pipeline-ci-project + 2.0.0-jdk17 + + + + cd.casic.pipeline + pipeline-ci-quality + 2.0.0-jdk17 + + + + cd.casic.pipeline + pipeline-ci-scm-repository + 2.0.0-jdk17 + + + + cd.casic.pipeline + pipeline-ci-ticket + 2.0.0-jdk17 + + + + + cd.casic.boot + spring-boot-starter-redis + + + + cd.casic.boot + spring-boot-starter-web + + + + cd.casic.boot + spring-boot-starter-monitor + + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/dal/package-info.java b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/dal/package-info.java new file mode 100644 index 0000000..8a3cddb --- /dev/null +++ b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/dal/package-info.java @@ -0,0 +1,7 @@ +/** + * @Classname package-info + * @Description TODO + * @Date 2025/3/21 18:58 + * @author by mianbin + */ +package cd.casic.pipeline.process.dal; \ No newline at end of file diff --git a/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/AESUtil.java b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/AESUtil.java new file mode 100644 index 0000000..7ca26e5 --- /dev/null +++ b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/AESUtil.java @@ -0,0 +1,86 @@ +package cd.casic.pipeline.process.utils; + +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PKCS7Padding; +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.Base64; + + +public class AESUtil { + + private static final String AES = "AES"; + private static final Integer SEED = 256; + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + public static String decrypt(String key, String content) { + byte[] bytes = Base64.getDecoder().decode(content); + KeyParameter keyParameter = generateKeyParameter(key); + byte[] output = processData(false, keyParameter, bytes); + return Base64.getEncoder().encodeToString(output); + } + + public static byte[] decrypt(String key, byte[] content) { + KeyParameter keyParameter = generateKeyParameter(key); + return processData(false, keyParameter, content); + } + + public static String encrypt(String key, String content) { + byte[] bytes = content.getBytes(StandardCharsets.UTF_8); + KeyParameter keyParameter = generateKeyParameter(key); + byte[] output = processData(true, keyParameter, bytes); + return Base64.getEncoder().encodeToString(output); + } + + public static byte[] encrypt(String key, byte[] content) { + KeyParameter keyParameter = generateKeyParameter(key); + return processData(true, keyParameter, content); + } + + private static byte[] processData(boolean encrypt, KeyParameter keyParameter, byte[] bytes) { + PKCS7Padding blockCipherPadding = new PKCS7Padding(); + CBCBlockCipher blockCipher = new CBCBlockCipher(new AESEngine()); + PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(blockCipher, blockCipherPadding); + paddedBufferedBlockCipher.init(encrypt, keyParameter); + + byte[] output = new byte[paddedBufferedBlockCipher.getOutputSize(bytes.length)]; + int offset = paddedBufferedBlockCipher.processBytes(bytes, 0, bytes.length, output, 0); + int outputLength = 0; + try { + outputLength = paddedBufferedBlockCipher.doFinal(output, offset); + } catch (InvalidCipherTextException e) { + e.printStackTrace(); + } + return Arrays.copyOf(output, offset + outputLength); + } + + private static KeyParameter generateKeyParameter(String key) { + KeyGenerator keyGenerator = null; + SecureRandom secureRandom = null; + try { + keyGenerator = KeyGenerator.getInstance(AES); + secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + e.printStackTrace(); + } + + keyGenerator.init(SEED, secureRandom); + SecretKey secretKey = keyGenerator.generateKey(); + byte[] encoded = secretKey.getEncoded(); + return new KeyParameter(encoded); + } +} diff --git a/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/CommonUtils.java b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/CommonUtils.java new file mode 100644 index 0000000..d9f6aeb --- /dev/null +++ b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/CommonUtils.java @@ -0,0 +1,16 @@ +package cd.casic.pipeline.process.utils; + + +public class CommonUtils { + + /** + * 获取字符串的头部指定长度 + */ + public static String interceptStringInLength(String string, Integer length) { + if (string != null && string.length() > length) { + return string.substring(0, length - 1); + } else { + return string; + } + } +} diff --git a/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/LogUtils.java b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/LogUtils.java new file mode 100644 index 0000000..67d5a0b --- /dev/null +++ b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/LogUtils.java @@ -0,0 +1,42 @@ +package cd.casic.pipeline.process.utils; + + +import cd.casic.framework.commons.util.watcher.Watcher; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LogUtils { + + /** + * 计算[watcher].createTime与当前时间的毫秒数的耗时在[warnThreshold]与[errorThreshold]之间, + * 会将[watcher]序列化为字符串并打印到WARN日志,当超出[errorThreshold]会打印ERROR日志。否则什么都不会打印 + */ + public static void printCostTimeWE(Watcher watcher, Long warnThreshold, Long errorThreshold){ + watcher.stop(); + long cost = System.currentTimeMillis() - watcher.getCreateTime(); + if (cost >= warnThreshold){ + if (cost > errorThreshold){ + log.error(watcher + " cost " + cost + " ms"); + } else { + log.warn(watcher + " cost " + cost + " ms"); + } + } + } + + public static void costTime(String message, Long startTime, Long warnThreshold, Long errorThreshold){ + long cost = System.currentTimeMillis() - startTime; + if (cost < warnThreshold) { + log.info(message + " cost " + cost + " ms"); + } + else if (cost >= warnThreshold && cost < errorThreshold) { + log.warn(message + " cost " + cost + " ms"); + } + else { + log.error(message + " cost " + cost + " ms"); + } + } + + public static void printCostTimeWE(Watcher watcher) { + printCostTimeWE(watcher, 1000L, 5000L); + } +} diff --git a/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/RetryUtils.java b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/RetryUtils.java new file mode 100644 index 0000000..a4f66c3 --- /dev/null +++ b/modules/pipeline-ci-process/src/main/java/cd/casic/pipeline/process/utils/RetryUtils.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.process.utils; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class RetryUtils { + + @SneakyThrows + public static T execute(Action action, Integer retryTime, Long retryPeriodMills) { + try { + return action.execute(); + } catch (Throwable ignored) { + if (retryTime - 1 <= 0) { + return action.fail(ignored); + } + Thread.sleep(retryPeriodMills); + return execute(action, retryTime - 1, 500L); + } + } + + public interface Action { + + T execute(); + + default T fail(Throwable e) throws Throwable { + throw e; + } + } +} diff --git a/modules/pipeline-ci-project/pom.xml b/modules/pipeline-ci-project/pom.xml new file mode 100644 index 0000000..cd87f57 --- /dev/null +++ b/modules/pipeline-ci-project/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-project + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + + cd.casic.boot + spring-boot-starter-redis + + + + cd.casic.boot + spring-boot-starter-web + + + + cd.casic.boot + spring-boot-starter-monitor + + + \ No newline at end of file diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/constant/ProjectConstants.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/constant/ProjectConstants.java new file mode 100644 index 0000000..d3d2101 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/constant/ProjectConstants.java @@ -0,0 +1,17 @@ +package cd.casic.pipeline.project.constant; + +/** + * @author by mianbin + * @Classname ProjectConstants + * @Description TODO + * @Date 2025/3/21 17:10 + */ +public class ProjectConstants { + public static final String EXCHANGE_PROJECT_COUNT_LOGIN = "exchange_project_count_login"; + public static final String ROUTE_PROJECT_COUNT_LOGIN = "route_project_count_login"; + public static final String QUEUE_PROJECT_COUNT_LOGIN = "queue_project_count_login"; + public static final String SECRECY_PROJECT_REDIS_KEY = "SECRECY_PROJECT_REDIS_KEY"; // 保密项目Key + + public static final Integer NAME_MAX_LENGTH = 64; + public static final Integer NAME_MIN_LENGTH = 2; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/controller/UserProjectResourceController.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/controller/UserProjectResourceController.java new file mode 100644 index 0000000..8ceb3b6 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/controller/UserProjectResourceController.java @@ -0,0 +1,39 @@ +package cd.casic.pipeline.project.controller; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; +import cd.casic.pipeline.project.service.UserProjectResourceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.*; + + + +@RestController +@Tag(name = "用户-项目列表接口") +@RequestMapping("/project") +public class UserProjectResourceController { + + @Resource + private UserProjectResourceService userProjectResourceService; + + @PostMapping + @Operation(summary = "创建项目") + public CommonResult create(@RequestBody ProjectCreateInfo projectCreateInfo, + @RequestHeader(name = "X-DEVOPS-ACCESS-TOKEN") String accessToken) { + return CommonResult.success(userProjectResourceService.create(getUserId(), projectCreateInfo, accessToken)); + } + + + private Long getUserId() { +// Long userId = SecurityFrameworkUtils.getLoginUserId(); +// if (userId == null) { +// throw new ServiceException("请登录!"); +// } +// return userId; + return 0L; + } + +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dao/ProjectMapper.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dao/ProjectMapper.java new file mode 100644 index 0000000..e2a6e02 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dao/ProjectMapper.java @@ -0,0 +1,21 @@ +package cd.casic.pipeline.project.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.project.dal.dto.Project; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateExtInfo; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; +import cd.casic.pipeline.project.dal.pojo.ProjectVO; +import cd.casic.pipeline.project.enums.ProjectChannelCode; +import cd.casic.pipeline.project.enums.ProjectValidateType; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ProjectMapper extends BaseMapperX { + + String create(Long userId, ProjectCreateInfo projectCreateInfo, String accessToken, + ProjectCreateExtInfo projectCreateExtInfo, String defaultProjectId, ProjectChannelCode projectChannelCode); + + void validate(ProjectValidateType validateType, String name, String projectId); + + ProjectVO getByProjectId(String projectId); +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dto/Project.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dto/Project.java new file mode 100644 index 0000000..af17709 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/dto/Project.java @@ -0,0 +1,236 @@ +package cd.casic.pipeline.project.dal.dto; + + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.util.Date; + +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "project", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class Project extends BaseDO { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + + private Long id; + + /** + * 删除时间 + */ + private Date deletedAt; + + /** + * 容器类型 + */ + private Integer kind; + + /** + * 应用ID + */ + private Long ccAppId; + + /** + * 应用名称 + */ + private String ccAppName; + + /** + * 是否停用 + */ + private Boolean isOfflined; + + /** + * 项目ID + */ + private String projectId; + + /** + * 项目名称 + */ + private String projectName; + + /** + * 英文名称 + */ + private String englishName; + + /** + * 项目类型 + */ + private Integer projectType; + + /** + * 是否用蓝鲸 + */ + private Boolean useBk; + + /** + * 事业群ID + */ + private Long bgId; + + /** + * 事业群名称 + */ + private String bgName; + + /** + * 项目所属二级机构ID + */ + private Long deptId; + + /** + * 项目所属二级机构名称 + */ + private String deptName; + + /** + * 中心ID + */ + private Long centerId; + + /** + * 中心名字 + */ + private String centerName; + + /** + * 数据ID + */ + private Long dataId; + + /** + * 是否保密 + */ + private Boolean isSecrecy; + + /** + * 是否启用图表激活 + */ + private Boolean isHelmChartEnabled; + + /** + * 审核状态 + */ + private Integer approvalStatus; + + /** + * 批准人 + */ + private String approver; + + /** + * 批准时间 + */ + private Date approvalTime; + + /** + * 创建者事业群名称 + */ + private String creatorBgName; + + /** + * 创建者项目所属二级机构名称 + */ + private String creatorDeptName; + + /** + * 创建者中心名字 + */ + private String creatorCenterName; + + /** + * 应用ID + */ + private Long hybridCcAppId; + + /** + * 是否支持构建机访问外网 + */ + private Boolean enableExternal; + + /** + * 是否支持IDC构建机 + */ + private Boolean enableIdc; + + /** + * 是否启用 + */ + private Boolean enabled; + + /** + * 项目渠道 + */ + private String channel; + + /** + * 流水线数量上限 + */ + private Integer pipelineLimit; + + /** + * 网关路由tags + */ + private String routerTag; + + /** + * 扩展系统关联ID + */ + private String relationId; + + /** + * 其他系统网关路由tags + */ + private String otherRouterTags; + + /** + * 项目性质,0-公开,1-保密,2-机密 + */ + private Integer authSecrecy; + + /** + * 额外信息 + */ + private String extra; + + /** + * 描述 + */ + private String description; + + /** + * 部署类型 + */ + private String deployType; + + /** + * logo地址 + */ + private String logoAddr; + + /** + * 评论 + */ + private String remark; + + /** + * 项目其他配置 + */ + private String properties; + + /** + * 最大可授权人员范围 + */ + private String subjectScopes; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/AuthProjectCreateInfo.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/AuthProjectCreateInfo.java new file mode 100644 index 0000000..999a502 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/AuthProjectCreateInfo.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.project.dal.pojo; + + +import cd.casic.pipeline.project.dal.pojo.user.UserDeptDetail; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Schema(description = "项目-资源创建模型") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AuthProjectCreateInfo { + + @Schema(description = "用户id") + private Long userId; + @Schema(description = "accessToken") + private String accessToken; + @Schema(description = "用户部门详细") + private UserDeptDetail userDeptDetail; + @Schema(description = "iamSubjectScopes") + private List subjectScopes; + @Schema(description = "projectCreateInfo") + private ProjectCreateInfo projectCreateInfo; + @Schema(description = "审批状态") + private Integer approvalStatus; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/PipelineAsCodeSettings.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/PipelineAsCodeSettings.java new file mode 100644 index 0000000..83b8c30 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/PipelineAsCodeSettings.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.project.dal.pojo; + +import lombok.Data; + +/** + * 设置-YAML流水线功能设置 + */ +@Data +public class PipelineAsCodeSettings { + + /** + * 是否支持流水线功能 + */ + private Boolean enable = false; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateExtInfo.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateExtInfo.java new file mode 100644 index 0000000..bb02038 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateExtInfo.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.project.dal.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ProjectCreateExtInfo { + + private Boolean needValidate; + private Boolean needAuth; + private Boolean needApproval; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateInfo.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateInfo.java new file mode 100644 index 0000000..e81fd7d --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectCreateInfo.java @@ -0,0 +1,45 @@ +package cd.casic.pipeline.project.dal.pojo; + +import cd.casic.pipeline.project.enums.ProjectAuthSecrecyStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +@Schema(description = "项目-新增模型") +@Data +public class ProjectCreateInfo { + @Schema(description = "项目名称") + private String projectName; + @Schema(description = "英文缩写") + private String englishName; + @Schema(description = "项目类型") + private int projectType = 0; + @Schema(description = "描述") + private String description; + @Schema(description = "一级部门ID") + private long bgId = 0; + @Schema(description = "一级部门名字") + private String bgName = ""; + @Schema(description = "二级部门ID") + private long deptId = 0; + @Schema(description = "二级部门名称") + private String deptName = ""; + @Schema(description = "三级部门ID") + private long centerId = 0; + @Schema(description = "三级部门名称") + private String centerName = ""; + @Schema(description = "是否保密") + private boolean secrecy = false; + @Schema(description = "kind") + private int kind = 0; + @Schema(description = "项目相关配置") + private ProjectProperties properties; + @Schema(description = "项目最大可授权人员范围") + private List subjectScopes = Collections.emptyList(); + @Schema(description = "logo地址") + private String logoAddress; + @Schema(description = "项目性质") + private Integer authSecrecy = ProjectAuthSecrecyStatus.PUBLIC.getValue(); +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectProperties.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectProperties.java new file mode 100644 index 0000000..faa670c --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectProperties.java @@ -0,0 +1,12 @@ +package cd.casic.pipeline.project.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "项目其他配置") +@Data +public class ProjectProperties { + + @Schema(description = "YAML流水线功能设置") + private PipelineAsCodeSettings pipelineAsCodeSettings; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectVO.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectVO.java new file mode 100644 index 0000000..7ef85e1 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ProjectVO.java @@ -0,0 +1,133 @@ +package cd.casic.pipeline.project.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "项目-显示模型") +public class ProjectVO { + + @Schema(description = "主键ID") + private Long id; + @Schema(description = "项目ID(很少使用)") + // @JsonProperty("project_id") + private String projectId; + @Schema(description = "项目名称") + // @JsonProperty("project_name") + private String projectName; + @Schema(description = "项目代码(蓝盾项目Id)") + // @JsonProperty("project_code") + private String projectCode; + @Schema(description = "项目类型") + // @JsonProperty("project_type") + private Integer projectType; + @Schema(description = "审批状态") + // @JsonProperty("approval_status") + private Integer approvalStatus; + @Schema(description = "审批时间") + // @JsonProperty("approval_time") + private String approvalTime; + @Schema(description = "审批人") + private String approver; + @Schema(description = "cc业务ID") + // @JsonProperty("cc_app_id") + private Long ccAppId; + @Schema(description = "cc业务名称") + // @JsonProperty("cc_app_name") + private String ccAppName; + @Schema(description = "创建时间") + // @JsonProperty("created_at") + private String createdAt; + @Schema(description = "创建人") + private Long creator; + @Schema(description = "数据ID") + // @JsonProperty("data_id") + private Long dataId; + @Schema(description = "部署类型") + // @JsonProperty("deploy_type") + private String deployType; + @Schema(description = "事业群ID") + // @JsonProperty("bg_id") + private String bgId; + @Schema(description = "事业群名字") + // @JsonProperty("bg_name") + private String bgName; + @Schema(description = "中心ID") + // @JsonProperty("center_id") + private String centerId; + @Schema(description = "中心名称") + // @JsonProperty("center_name") + private String centerName; + @Schema(description = "部门ID") + // @JsonProperty("dept_id") + private String deptId; + @Schema(description = "部门名称") + // @JsonProperty("dept_name") + private String deptName; + @Schema(description = "描述") + private String description; + @Schema(description = "英文缩写") + // @JsonProperty("english_name") + private String englishName; + @Schema(description = "extra") + private String extra; + @Schema(description = "是否离线") + // @get; + private Boolean offlined; + @Schema(description = "是否保密") + // @get; + private Boolean secrecy; + @Schema(description = "是否启用图表激活") + // @get; + private Boolean helmChartEnabled; + @Schema(description = "kind") + private Integer kind; + @Schema(description = "logo地址") + // @JsonProperty("logo_addr") + private String logoAddr; + @Schema(description = "评论") + private String remark; + @Schema(description = "修改时间") + // @JsonProperty("updated_at") + private String updatedAt; + @Schema(description = "修改人") + // @JsonProperty("updated_at") + private String updator; + @Schema(description = "useBK") + // @JsonProperty("use_bk") + private Boolean useBk; + @Schema(description = "启用") + private Boolean enabled; + @Schema(description = "是否灰度") + private Boolean gray; + @Schema(description = "混合云CC业务ID") + private Long hybridCcAppId; + @Schema(description = "支持构建机访问外网") + private Boolean enableExternal; + @Schema(description = "支持IDC构建机") + private Boolean enableIdc; + @Schema(description = "流水线数量上限") + private Integer pipelineLimit; + @Schema(description = "项目路由指向") + private String routerTag; + @Schema(description = "关联系统Id") + private String relationId; + @Schema(description = "项目其他配置") + private ProjectProperties properties; + @Schema(description = "项目最大可授权人员范围") + private List subjectScopes; + @Schema(description = "是否权限私密") + private Integer authSecrecy; + @Schema(description = "项目提示状态,0-不展示,1-展示创建成功,2-展示编辑成功") + private Integer tipsStatus; + @Schema(description = "项目审批message") + private String approvalMsg; + @Schema(description = "是否拥有新版权限中心项目管理权限") + private Boolean managePermission; + @Schema(description = "是否展示用户管理图标") + private Boolean showUserManageIcon; + @Schema(description = "渠道") + private String channelCode; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ResourceRegisterInfo.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ResourceRegisterInfo.java new file mode 100644 index 0000000..cdfc7e7 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/ResourceRegisterInfo.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline.project.dal.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ResourceRegisterInfo { + private String resourceCode; + private String resourceName; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/SubjectScopeInfo.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/SubjectScopeInfo.java new file mode 100644 index 0000000..541cdbb --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/SubjectScopeInfo.java @@ -0,0 +1,25 @@ +package cd.casic.pipeline.project.dal.pojo; + +import cd.casic.pipeline.commons.enums.SubjectScopeType; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(description = "授权范围") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SubjectScopeInfo { + @Schema(description = "ID") + private String id; + @Schema(description = "name") + private String name; + @Schema(description = "类型") + private String type = SubjectScopeType.USER.getValue(); + @JsonProperty("full_name") + private String fullName; + @Schema(description = "用户名") + private String username; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/user/UserDeptDetail.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/user/UserDeptDetail.java new file mode 100644 index 0000000..41f96f9 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/dal/pojo/user/UserDeptDetail.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.project.dal.pojo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "用户部门信息") +public class UserDeptDetail { + @Schema(description = "bg名称") + private String bgName; + @Schema(description = "bgID") + private String bgId; + @Schema(description = "部门名称") + private String deptName; + @Schema(description = "部门ID") + private String deptId; + @Schema(description = "中心名称") + private String centerName; + @Schema(description = "中心ID") + private String centerId; + @Schema(description = "组ID") + private String groupId; + @Schema(description = "组名称") + private String groupName; + @Schema(description = "用户ID") + private Long userId; + @Schema(description = "用户名称") + private String name; +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectApproveStatus.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectApproveStatus.java new file mode 100644 index 0000000..1e7a4b9 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectApproveStatus.java @@ -0,0 +1,45 @@ +package cd.casic.pipeline.project.enums; + +public enum ProjectApproveStatus { + UNKNOWN(-1), + + // 创建审批中 + CREATE_PENDING(1), + + // 审批通过 + APPROVED(2), + + // 创建中审批拒绝 + CREATE_REJECT(3), + + // 修改审批中 + UPDATE_PENDING(4); + + private final Integer status; + + ProjectApproveStatus(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + public boolean isSuccess() { + return this == APPROVED || this == UPDATE_PENDING; + } + + public boolean isCreatePending() { + return this == CREATE_PENDING || this == CREATE_REJECT; + } + + public static ProjectApproveStatus parse(int status) { + for (ProjectApproveStatus value : values()) { + if (value.getStatus() == status) { + return value; + } + } + + return null; + } +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectAuthSecrecyStatus.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectAuthSecrecyStatus.java new file mode 100644 index 0000000..07cf7db --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectAuthSecrecyStatus.java @@ -0,0 +1,32 @@ +package cd.casic.pipeline.project.enums; + +public enum ProjectAuthSecrecyStatus { + PUBLIC(0, "私有项目"), + PRIVATE(1, "保密项目"), + CLASSIFIED(2, "机密项目"); + + private final Integer value; + private final String desc; + + ProjectAuthSecrecyStatus(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + public Integer getValue() { + return value; + } + + public String getDesc() { + return desc; + } + + public static ProjectAuthSecrecyStatus getStatus(int status) { + for (ProjectAuthSecrecyStatus secrecyStatus : values()) { + if (secrecyStatus.value == status) { + return secrecyStatus; + } + } + return null; + } +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectChannelCode.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectChannelCode.java new file mode 100644 index 0000000..9db052a --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectChannelCode.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.project.enums; + +import io.swagger.v3.oas.annotations.media.Schema; + + +@Schema(description = "项目道代码") +public enum ProjectChannelCode { + @Schema(description = "蓝盾") + BS, + @Schema(description = "PREBULD") + PREBUILD, + @Schema(description = "CODECC") + CODECC, + @Schema(description = "GITCI") + GITCI, + @Schema(description = "自动化集群项目,区分于CODECC项目") + AUTO +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectValidateType.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectValidateType.java new file mode 100644 index 0000000..64f0fb2 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/enums/ProjectValidateType.java @@ -0,0 +1,6 @@ +package cd.casic.pipeline.project.enums; + +public enum ProjectValidateType { + PROJECT_NAME, + ENGLISH_NAME +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectExtService.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectExtService.java new file mode 100644 index 0000000..d9b6d34 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectExtService.java @@ -0,0 +1,9 @@ +package cd.casic.pipeline.project.service; + + +import cd.casic.pipeline.project.dal.pojo.ProjectCreateExtInfo; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; + +public interface ProjectExtService { + void createExtProjectInfo(Long userId, String projectId, String accessToken, ProjectCreateInfo projectCreateInfo, ProjectCreateExtInfo createExtInfo, String logoAddress); +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectPermissionService.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectPermissionService.java new file mode 100644 index 0000000..f105831 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/ProjectPermissionService.java @@ -0,0 +1,8 @@ +package cd.casic.pipeline.project.service; + +import cd.casic.pipeline.project.dal.pojo.AuthProjectCreateInfo; +import cd.casic.pipeline.project.dal.pojo.ResourceRegisterInfo; + +public interface ProjectPermissionService { + String createResources(ResourceRegisterInfo resourceRegisterInfo, AuthProjectCreateInfo authProjectCreateInfo); +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/UserProjectResourceService.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/UserProjectResourceService.java new file mode 100644 index 0000000..6fb874a --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/UserProjectResourceService.java @@ -0,0 +1,9 @@ +package cd.casic.pipeline.project.service; + + +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; + +public interface UserProjectResourceService { + + boolean create(Long userId, ProjectCreateInfo projectCreateInfo, String accessToken); +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/BluekingProjectPermissionServiceImpl.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/BluekingProjectPermissionServiceImpl.java new file mode 100644 index 0000000..3392232 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/BluekingProjectPermissionServiceImpl.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.project.service.impl; + +import cd.casic.pipeline.project.dal.pojo.AuthProjectCreateInfo; +import cd.casic.pipeline.project.dal.pojo.ResourceRegisterInfo; +import cd.casic.pipeline.project.service.ProjectPermissionService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class BluekingProjectPermissionServiceImpl implements ProjectPermissionService { + @Override + public String createResources(ResourceRegisterInfo resourceRegisterInfo, AuthProjectCreateInfo authProjectCreateInfo) { + List projectList = new ArrayList<>(); + return ""; + } +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectExtServiceImpl.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectExtServiceImpl.java new file mode 100644 index 0000000..65a924d --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectExtServiceImpl.java @@ -0,0 +1,16 @@ +package cd.casic.pipeline.project.service.impl; + + +import cd.casic.pipeline.project.dal.pojo.ProjectCreateExtInfo; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; +import cd.casic.pipeline.project.service.ProjectExtService; +import org.springframework.stereotype.Service; + +@Service("projectExtService") +public class ProjectExtServiceImpl implements ProjectExtService { + @Override + public void createExtProjectInfo(Long userId, String projectId, String accessToken, ProjectCreateInfo projectCreateInfo, ProjectCreateExtInfo createExtInfo, String logoAddress) { + //TODO 调用另一个服务 + //client.get(ServiceBkRepoResource::class).createProjectResource(userId, projectCreateInfo.englishName) + } +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectServiceImpl.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectServiceImpl.java new file mode 100644 index 0000000..2efeb33 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/ProjectServiceImpl.java @@ -0,0 +1,209 @@ +package cd.casic.pipeline.project.service.impl; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.util.json.JsonUtils; +import cd.casic.framework.redis.core.RedisTemplateUtils; +import cd.casic.pipeline.commons.constant.BaseConstant; +import cd.casic.pipeline.project.constant.ProjectConstants; +import cd.casic.pipeline.project.dal.dao.ProjectMapper; +import cd.casic.pipeline.project.dal.dto.Project; +import cd.casic.pipeline.project.dal.pojo.*; +import cd.casic.pipeline.project.dal.pojo.user.UserDeptDetail; +import cd.casic.pipeline.project.enums.ProjectApproveStatus; +import cd.casic.pipeline.project.enums.ProjectAuthSecrecyStatus; +import cd.casic.pipeline.project.enums.ProjectChannelCode; +import cd.casic.pipeline.project.enums.ProjectValidateType; +import cd.casic.pipeline.project.service.ProjectExtService; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + + +@Service("projectService") +@Slf4j +public class ProjectServiceImpl { + + private final String ENGLISH_NAME_PATTERN = "[a-z][a-zA-Z0-9-]+"; + private final String ALL_MEMBERS = "*"; + private final String ALL_MEMBERS_NAME = "allMembersName"; + private final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + @Resource + private ProjectExtService projectExtService; + @Resource + private ProjectMapper projectMapper; + @Resource + private RedisTemplateUtils redisTemplateUtils; + + public String create(Long userId, ProjectCreateInfo projectCreateInfo, String accessToken, + ProjectCreateExtInfo createExtInfo, String defaultProjectId, ProjectChannelCode projectChannelCode) { + + log.info("create project| {} | {} | {} | {}", userId, accessToken, createExtInfo, projectCreateInfo); + if (createExtInfo.getNeedValidate()) { + validate(ProjectValidateType.PROJECT_NAME, projectCreateInfo.getProjectName(), null); + validate(ProjectValidateType.ENGLISH_NAME, projectCreateInfo.getEnglishName(), null); + } + UserDeptDetail userDeptDetail = getDeptInfo(userId); + String projectId = defaultProjectId; + List subjectScopes = projectCreateInfo.getSubjectScopes(); + if (subjectScopes == null || subjectScopes.isEmpty()) { + subjectScopes = Collections.singletonList(new SubjectScopeInfo(ALL_MEMBERS, getAllMembersName(), ALL_MEMBERS, null, null)); + } + //TODO 待完善 先直接得到结果 +// boolean needApproval = projectPermissionService.needApproval(createExtInfo.getNeedApproval()); + boolean needApproval = false; + int approvalStatus = needApproval ? ProjectApproveStatus.CREATE_PENDING.getStatus() : + ProjectApproveStatus.APPROVED.getStatus(); + + //这一块bk-ci未具体实现 +// try { +// if (createExtInfo.getNeedAuth()) { +// AuthProjectCreateInfo authProjectCreateInfo = new AuthProjectCreateInfo(userId, accessToken, +// userDeptDetail, subjectScopes, projectCreateInfo, approvalStatus); +// // 注册项目到权限中心(bk-ci未具体实现,只是一个空方法) +// projectId = projectPermissionService.createResources( +// new ResourceRegisterInfo(projectCreateInfo.getEnglishName(), +// projectCreateInfo.getProjectName()), authProjectCreateInfo); +// } +// } catch (PermissionForbiddenException e) { +// throw e; +// } catch (Exception e) { +// logger.warn("Failed to create project in permission center: {} | {}", projectCreateInfo, e.getMessage()); +// throw new OperationException(I18nUtil.getCodeLanMessage(ProjectMessageCode.PEM_CREATE_FAIL)); +// } + if (StringUtils.isEmpty(projectId)) { + projectId = IdUtil.simpleUUID(); + } + try { + String subjectScopesStr = JsonUtils.toJsonString(subjectScopes); + String logoAddress = projectCreateInfo.getLogoAddress(); + + create(userId, logoAddress, projectCreateInfo, userDeptDetail, projectId, + projectChannelCode, approvalStatus, subjectScopesStr); + if (!needApproval) { + projectExtService.createExtProjectInfo(userId, projectId, accessToken, projectCreateInfo, + createExtInfo, logoAddress); + } + // 为项目分配数据源 +// shardingRoutingRuleAssignService.assignShardingRoutingRule(projectChannelCode, +// projectCreateInfo.getEnglishName(), Arrays.asList(SystemModuleEnum.PROCESS, SystemModuleEnum.METRICS)); + if (projectCreateInfo.isSecrecy()) { + redisTemplateUtils.set(ProjectConstants.SECRECY_PROJECT_REDIS_KEY, projectCreateInfo.getEnglishName()); + } + updateProjectRouterTag(projectCreateInfo.getEnglishName()); + } catch (Exception e) { + log.warn("Duplicate project: {}", projectCreateInfo, e); + if (createExtInfo.getNeedAuth()) { + // todo 待确定,切换v3-RBAC后,是否需要做其他操作 + +// deleteAuth(projectId, accessToken); + } + throw new ServiceException(-1000, "项目名或英文名重复"); + } catch (Throwable e) { + log.warn("Fail to create the project: {}", projectCreateInfo, e); + if (createExtInfo.getNeedAuth()) { +// deleteAuth(projectId, accessToken); + } + throw e; + } + return projectId; + } + + private void updateProjectRouterTag(String englishName) { + } + + private String getAllMembersName() { + //TODO +// return I18nUtil.getCodeLanMessage(ALL_MEMBERS_NAME); + return "allMembersName"; + } + + private UserDeptDetail getDeptInfo(Long userId) { + UserDeptDetail detail = new UserDeptDetail(); + detail.setUserId(userId); + detail.setBgId("1"); + detail.setCenterId("1"); + detail.setDeptId("1"); + + return detail; + } + + + public void validate(ProjectValidateType validateType, String name, String projectId) { +// if (StringUtils.isBlank(name)) { +// throw new ServiceException(-1000, "项目名称不能为空"); +// } +// if (validateType == ProjectValidateType.PROJECT_NAME) { +// if (name.isEmpty() || name.length() > ProjectConstants.NAME_MAX_LENGTH) { +// throw new ServiceException(-1000, "项目名至多1-64个字符"); +// } +// LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() +// .eq(Project::getProjectName, name); +// if (StringUtils.isNotBlank(projectId)) { +// wrapper.ne(Project::getProjectId, projectId); +// } +// +// if (this.exist(wrapper)) { +// throw new ServiceException(-1000, "项目名或英文名重复"); +// } +// } else if (validateType == ProjectValidateType.ENGLISH_NAME) { +// if (name.length() < ProjectConstants.NAME_MIN_LENGTH || name.length() > ProjectConstants.NAME_MAX_LENGTH) { +// throw new ServiceException(-1000, "英文名长度在3-64个字符"); +// } +// if (!Pattern.matches(ENGLISH_NAME_PATTERN, name)) { +// log.warn("Project English Name({}) is not match", name); +// throw new ServiceException(-1000, "英文名是字符+数字组成,并以小写字母开头"); +// } +// +// LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() +// .eq(Project::getEnglishName, name); +// if (StringUtils.isNotBlank(projectId)) { +// queryWrapper.ne(Project::getProjectId, projectId); +// } +// if (this.exist(queryWrapper)) { +// throw new ServiceException(-1000, "英文名已经存在"); +// } +// } + } + + public ProjectVO getByProjectId(String projectId) { + Project one = projectMapper.selectOne(Project::getProjectId, projectId, Project::getDeleted, BaseConstant.NOT_DELETED); + ProjectVO convert = Convert.convert(ProjectVO.class, one); + convert.setProjectCode(one.getEnglishName() == null ? "" : one.getEnglishName()); + convert.setGray("gray".equals(one.getRouterTag())); + convert.setChannelCode(one.getChannel()); + convert.setUpdator(one.getUpdater()); + convert.setCreatedAt(DateUtil.format(one.getCreateTime(), YYYY_MM_DD_HH_MM_SS)); + convert.setUpdatedAt(DateUtil.format(one.getUpdateTime(), YYYY_MM_DD_HH_MM_SS)); + convert.setApprovalTime(DateUtil.format(one.getApprovalTime(), YYYY_MM_DD_HH_MM_SS)); + convert.setProperties(JsonUtils.parseObject(one.getProperties(), ProjectProperties.class)); + convert.setSubjectScopes(JsonUtils.parseArray(one.getSubjectScopes(), SubjectScopeInfo.class)); + return convert; + } + + private void create(Long userId, String logoAddress, ProjectCreateInfo projectCreateInfo, UserDeptDetail userDeptDetail, + String projectId, ProjectChannelCode channelCode, Integer approvalStatus, String subjectScopesStr) { + Project project = Convert.convert(Project.class, projectCreateInfo); + project.setProjectId(projectId); + project.setCreator(userId.toString()); + project.setApprovalStatus(approvalStatus); + project.setLogoAddr(logoAddress == null ? "" : logoAddress); + project.setCreatorBgName(projectCreateInfo.getBgName()); + project.setCreatorDeptName(projectCreateInfo.getBgName()); + project.setCreatorCenterName(projectCreateInfo.getCenterName()); + project.setChannel(channelCode != null ? channelCode.name() : null); + project.setEnabled(true); + project.setProperties(projectCreateInfo.getProperties() != null ? JsonUtils.toJsonString(projectCreateInfo.getProperties()) : null); + project.setSubjectScopes(subjectScopesStr); + project.setAuthSecrecy(projectCreateInfo.getAuthSecrecy() == null ? ProjectAuthSecrecyStatus.PUBLIC.getValue() : projectCreateInfo.getAuthSecrecy()); + projectMapper.insert(project); + } +} diff --git a/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/UserProjectResourceServiceImpl.java b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/UserProjectResourceServiceImpl.java new file mode 100644 index 0000000..d618277 --- /dev/null +++ b/modules/pipeline-ci-project/src/main/java/cd/casic/pipeline/project/service/impl/UserProjectResourceServiceImpl.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.project.service.impl; + + +import cd.casic.pipeline.project.dal.dao.ProjectMapper; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateExtInfo; +import cd.casic.pipeline.project.dal.pojo.ProjectCreateInfo; +import cd.casic.pipeline.project.enums.ProjectChannelCode; +import cd.casic.pipeline.project.service.UserProjectResourceService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@Service("userProjectResourceService") +public class UserProjectResourceServiceImpl implements UserProjectResourceService { + + @Resource + private ProjectMapper projectService; + + @Override + @Transactional(rollbackFor = Throwable.class) + public boolean create(Long userId, ProjectCreateInfo projectCreateInfo, String accessToken) { + + ProjectCreateExtInfo projectCreateExtInfo = new ProjectCreateExtInfo(true, true, true); + projectService.create(userId, projectCreateInfo, accessToken, projectCreateExtInfo, + null, ProjectChannelCode.BS); + + return true; + } +} diff --git a/modules/pipeline-ci-quality/pom.xml b/modules/pipeline-ci-quality/pom.xml new file mode 100644 index 0000000..7a3ff75 --- /dev/null +++ b/modules/pipeline-ci-quality/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-quality + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/api/ServiceQualityRuleResource.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/api/ServiceQualityRuleResource.java new file mode 100644 index 0000000..6a0dfd9 --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/api/ServiceQualityRuleResource.java @@ -0,0 +1,31 @@ +package cd.casic.pipeline.api; + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.dal.pojo.RuleCheckResult; +import cd.casic.pipeline.dal.v3.request.BuildCheckParamsV3; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author by mianbin + * @Classname ServiceQualityRuleResource + * @Date 2025/3/20 20:01 + */ +@RestController +@Tag(name = "质量红线-规则v3") +@RequestMapping("/service/rules/v3") +public class ServiceQualityRuleResource { + // TODO 待完善 + @Operation(summary = "检查是否通过控制点") + @PostMapping("/check") + public CommonResult check(@Parameter(description = "构建检查参数", required = true) + @RequestParam + BuildCheckParamsV3 buildCheckParams) { + return null; + } +} diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/constants/QualityConstants.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/constants/QualityConstants.java new file mode 100644 index 0000000..d22f832 --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/constants/QualityConstants.java @@ -0,0 +1,67 @@ +package cd.casic.pipeline.constants; + +/** + * @author by mianbin + * @Classname QualityConstants + * @Date 2025/3/20 19:58 + */ +public class QualityConstants { + public static final String QUALITY_RULE_TEMPLATE_NAME_KEY = "quality.ruleTemplate.%s.name"; // $s == ID + public static final String QUALITY_RULE_TEMPLATE_DESC_KEY = "quality.ruleTemplate.%s.desc"; // $s == ID + public static final String QUALITY_RULE_TEMPLATE_STAGE_KEY = "quality.ruleTemplate.%s.stage"; // $s == ID + public static final String QUALITY_CONTROL_POINT_NAME_KEY = "quality.controlPoint.%s.name"; // $s == elementType + public static final String QUALITY_CONTROL_POINT_STAGE_KEY = "quality.controlPoint.%s.stage"; // $s == elementType + public static final String QUALITY_METADATA_DATA_NAME_KEY = "quality.metadata.%s.dataName"; // $s == ID + public static final String QUALITY_METADATA_DATA_ELEMENT_NAME_KEY = "quality.metadata.%s.elementName"; // $s == ID + public static final String QUALITY_METADATA_DATA_DESC_KEY = "quality.metadata.%s.desc"; // $s == ID + public static final String QUALITY_INDICATOR_ELEMENT_NAME_KEY = "quality.indicator.%s.elementName"; // $s == ID + public static final String QUALITY_INDICATOR_NAME_KEY = "quality.indicator.%s.name"; // $s == ID + public static final String QUALITY_INDICATOR_DESC_KEY = "quality.indicator.%s.desc"; // $s == ID + public static final String BK_BEFORE_POSITION = "bkBeforePosition"; // 准入-满足条件才能执行控制点 + public static final String BK_AFTER_POSITION = "bkAfterPosition"; // 准出-满足条件才能执行后续插件 + public static final String BK_PROJECT_UNDER_NO_QUALITY_USER_GROUP = "bkProjectUnderNoQualityUserGroup"; // 项目下无Quality用户组 + public static final String BK_PASSED = "bkPassed"; // 已通过: + public static final String BK_BLOCKED = "bkBlocked"; // 已拦截: + public static final String BK_CURRENT_VALUE = "bkCurrentValue"; // {0}当前值({1}),期望{2} + public static final String BK_VALIDATION_PASSED = "bkValidationPassed"; // {0}(#{1})在{2}验证通过 + public static final String BK_VALIDATION_INTERCEPTED = "bkValidationIntercepted"; // {0}(#{1})在{2}验证被拦截 + public static final String BK_INTERCEPTION_RULES = "bkInterceptionRules"; // 拦截规则 + public static final String BK_INTERCEPTION_METRICS = "bkInterceptionMetrics"; // 拦截指标 + public static final String BK_BUILD_INTERCEPTED_TO_BE_REVIEWED = "bkBuildInterceptedToBeReviewed"; // {0}({1})被拦截,待审核(审核人{2}) + public static final String BK_BUILD_INTERCEPTED_TERMINATED = "bkBuildInterceptedTerminated"; // {0}(#{1})被拦截,已终止 + public static final String BK_NO_TOOL_OR_RULE_ENABLED = "bkNoToolOrRuleEnabled"; // 你可能并未添加工具或打开相应规则。 + // 用户没有拦截规则{0}权限 + public static final String BK_USER_NO_OPERATE_INTERCEPT_RULE_PERMISSION = "bkUserNoOperateInterceptRulePermission"; + public static final String BK_CREATE_SUCCESS = "bkCreateSuccess"; // 创建成功 + public static final String BK_CREATE_FAIL = "bkCreateFail"; // 未知的异常,创建失败 + public static final String BK_UPDATE_FAIL = "bkUpdateFail"; // 未知的异常,更新失败 + public static final String BK_METRIC_DATA_UPDATE_SUCCESS = "bkMetricDataUpdateSuccess"; // 更新指标数据成功 + public static final String BK_TOOL_DESC_STANDARD = "bkToolDescStandard"; // 代码规范 + public static final String BK_TOOL_DESC_DEFECT = "bkToolDescDefect"; // 代码缺陷 + public static final String BK_TOOL_DESC_SECURITY = "bkToolDescSecurity"; // 安全漏洞 + public static final String BK_TOOL_DESC_RIPS = "bkToolDescRips"; // 啄木鸟漏洞扫描 + public static final String BK_TOOL_DESC_SENSITIVE = "bkToolDescSensitive"; // 敏感信息 + public static final String BK_TOOL_DESC_WOODPECKER_SENSITIVE = "bkToolDescWoodpeckerSensitive"; // 啄木鸟敏感信息 + public static final String BK_TOOL_DESC_CCN = "bkToolDescCcn"; // 圈复杂度 + public static final String BK_TOOL_DESC_DUPC = "bkToolDescDupc"; // 重复率 + public static final String BK_TOOL_NAME_STANDARD = "bkToolNameStandard"; // 按维度(推荐) + public static final String BK_TOOL_NAME_DEFECT = "bkToolNameDefect"; // 按维度(推荐) + public static final String BK_TOOL_NAME_SECURITY = "bkToolNameSecurity"; // 按维度(推荐) + public static final String BK_TOOL_NAME_CCN = "bkToolNameCcn"; // 通过计算函数的节点个数来衡量代码复杂性 + public static final String BK_TOOL_NAME_DUPC = "bkToolNameDupc"; // 可以检测项目中复制粘贴和重复开发相同功能等问题 + public static final String BK_TOOL_NAME_COVERITY = "bkToolNameCoverity"; // 斯坦福大学科学家研究成果,静态源代码分析领域的领导者 + public static final String BK_TOOL_NAME_KLOCWORK = "bkToolNameKlocwork"; // 业界广泛使用的商用代码检查工具,与Coverity互补 + public static final String BK_TOOL_NAME_CPPLINT = "bkToolNameCpplint"; // 谷歌开源的C++代码风格检查工具 + public static final String BK_TOOL_NAME_ESLINT = "bkToolNameEslint"; // JavaScript代码检查工具 + public static final String BK_TOOL_NAME_PYLINT = "bkToolNamePylint"; // Python代码风格检查工具 + public static final String BK_TOOL_NAME_GOML = "bkToolNameGoml"; // Golang静态代码分析工具 + public static final String BK_TOOL_NAME_CHECKSTYLE = "bkToolNameCheckstyle"; // Java代码风格检查工具 + public static final String BK_TOOL_NAME_STYLECOP = "bkToolNameStylecop"; // 微软开源的C#静态代码分析工具 + public static final String BK_TOOL_NAME_DETEKT = "bkToolNameDetekt"; // Kotlin静态代码分析工具 + public static final String BK_TOOL_NAME_PHPCS = "bkToolNamePhpcs"; // PHP代码风格检查工具 + public static final String BK_TOOL_NAME_SENSITIVE = "bkToolNameSensitive"; // 可扫描代码中有安全风险的敏感信息 + public static final String BK_TOOL_NAME_OCCHECK = "bkToolNameOccheck"; // OC代码风格检查工具 + public static final String BK_TOOL_NAME_WOODPECKER_SENSITIVE = "bkToolNameWoodpeckerSensitive"; // 敏感信息检查工具 + public static final String BK_TOOL_NAME_BKCHECK_CPP = "bkToolNameBkcheckCpp"; // C++代码风格检查工具 + public static final String BK_TOOL_NAME_BKCHECK_OC = "bkToolNameBkcheckOc"; // OC代码风格检查工具 +} diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/package-info.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/package-info.java new file mode 100644 index 0000000..3f5cf9d --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/package-info.java @@ -0,0 +1,7 @@ +/** + * @Classname package-info + * @Description TODO + * @Date 2025/3/20 19:59 + * @author by mianbin + */ +package cd.casic.pipeline.dal; \ No newline at end of file diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckResult.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckResult.java new file mode 100644 index 0000000..ba95119 --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckResult.java @@ -0,0 +1,23 @@ +package cd.casic.pipeline.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + + +@Data +@Schema(description = "质量红线-拦截检测结果") +public class RuleCheckResult { + + @Schema(description = "是否通过", requiredMode = Schema.RequiredMode.REQUIRED) + private Boolean success; + @Schema(description = "失败后是否结束", requiredMode = Schema.RequiredMode.REQUIRED) + private Boolean failEnd; + @Schema(description = "审核超时时间", requiredMode = Schema.RequiredMode.REQUIRED) + private Long auditTimeoutSeconds; + @Schema(description = "第几次检查", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer checkTimes; + @Schema(description = "失败信息", requiredMode = Schema.RequiredMode.REQUIRED) + private List resultList; +} diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckSingleResult.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckSingleResult.java new file mode 100644 index 0000000..d18aa5b --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/pojo/RuleCheckSingleResult.java @@ -0,0 +1,14 @@ +package cd.casic.pipeline.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.commons.lang3.tuple.Triple; + +import java.util.List; + +@Schema(description = "质量红线-单条规则拦截结果") +public class RuleCheckSingleResult { + + private String name; + + private List> messagePairs; +} diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v2/ControlPointPosition.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v2/ControlPointPosition.java new file mode 100644 index 0000000..2af891e --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v2/ControlPointPosition.java @@ -0,0 +1,37 @@ +package cd.casic.pipeline.dal.v2; + +import cd.casic.pipeline.constants.QualityConstants; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author by mianbin + * @Classname ControlPointPosition + * @Date 2025/3/20 19:59 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ControlPointPosition { + private String name; + private String code; + + public static final String BEFORE_POSITION = "BEFORE"; + public static final String AFTER_POSITION = "AFTER"; + + private static Map POSITION_NAME_MAP = new HashMap<>(); + + static { + POSITION_NAME_MAP.put(BEFORE_POSITION, QualityConstants.BK_BEFORE_POSITION); + POSITION_NAME_MAP.put(AFTER_POSITION, QualityConstants.BK_AFTER_POSITION); + } + + public static ControlPointPosition create(String code) { + String name = POSITION_NAME_MAP.get(code); + return new ControlPointPosition(code, name); + } +} diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/package-info.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/package-info.java new file mode 100644 index 0000000..eb2dfbd --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/package-info.java @@ -0,0 +1,7 @@ +/** + * @Classname package-info + * @Description TODO + * @Date 2025/3/20 20:00 + * @author by mianbin + */ +package cd.casic.pipeline.dal.v3; \ No newline at end of file diff --git a/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/request/BuildCheckParamsV3.java b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/request/BuildCheckParamsV3.java new file mode 100644 index 0000000..0e843bd --- /dev/null +++ b/modules/pipeline-ci-quality/src/main/java/cd/casic/pipeline/dal/v3/request/BuildCheckParamsV3.java @@ -0,0 +1,39 @@ +package cd.casic.pipeline.dal.v3.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; +import java.util.Set; + +/** + * @author by mianbin + * @Classname BuildCheckParamsV3 + * @Date 2025/3/20 20:00 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "构建参数检查") +public class BuildCheckParamsV3 { + + private String projectId; + + private String pipelineId; + + private String buildId; + + private String position; + + private String templateId; + + private String interceptName; + + private Set ruleBuildIds; + + private String stageId; + + private Map runtimeVariable; +} diff --git a/modules/pipeline-ci-scm-repository/pom.xml b/modules/pipeline-ci-scm-repository/pom.xml new file mode 100644 index 0000000..a9a2d34 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-scm-repository + + ${revision} + + + + cd.casic.pipeline + pipeline-ci-commons + + + cd.casic.boot + spring-boot-starter-mybatis + + + cd.casic.boot + spring-boot-starter-redis + + + + org.hashids + hashids + 1.0.3 + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/Main.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/Main.java new file mode 100644 index 0000000..19d4be1 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/Main.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline; + +/** + * @author by mianbin + * @Classname ${NAME} + * @Description TODO + * @Date 2025/3/20 20:10 + */ +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResource.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResource.java new file mode 100644 index 0000000..bf6ad2e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResource.java @@ -0,0 +1,59 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.github.GithubBranch; +import cd.casic.pipeline.scm.dal.pojo.github.GithubTag; +import cd.casic.pipeline.scm.dal.pojo.github.GithubToken; +import cd.casic.pipeline.scm.enums.GitHubTokenType; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Tag(name = "服务-github相关") +@RequestMapping("/service/github") +public interface ServiceGithubResource { + + @Operation(summary = "获取github代码库accessToken") + @GetMapping("/accessToken") + CommonResult getAccessToken( + @Parameter(name = "userId", description = "用户ID", required = true) + @RequestParam(name = "userId") + String userId, + @Parameter(description = "token 类型", required = false) + @RequestParam(name = "tokenType",defaultValue = "GITHUB_APP") + GitHubTokenType gitHubTokenType + ); + + @Operation(summary = "获取github指定分支") + @GetMapping("/getGithubBranch") + CommonResult getGithubBranch( + @Parameter(name = "accessToken", required = true) + @RequestParam(name = "accessToken") + String accessToken, + @Parameter(name = "projectName", required = true) + @RequestParam(name = "projectName") + String projectName, + @Parameter(name = "branch", required = false) + @RequestParam(name = "branch") + String branch); + + @Operation(summary = "获取github指定tag") + @GetMapping("/getGithubTag") + CommonResult getGithubTag( + @Parameter(name = "accessToken", required = true) + @RequestParam(name = "accessToken") + String accessToken, + @Parameter(name = "projectName", required = true) + @RequestParam(name = "projectName") + String projectName, + @Parameter(name = "tag", required = true) + @RequestParam(name = "tag") + String tag + ); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResourceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResourceImpl.java new file mode 100644 index 0000000..84ee68c --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceGithubResourceImpl.java @@ -0,0 +1,43 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.github.GithubBranch; +import cd.casic.pipeline.scm.dal.pojo.github.GithubTag; +import cd.casic.pipeline.scm.dal.pojo.github.GithubToken; +import cd.casic.pipeline.scm.enums.GitHubTokenType; +import cd.casic.pipeline.scm.service.github.GithubTokenService; +import cd.casic.pipeline.scm.service.github.IGithubService; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.RestController; + + +/** + * @author liubin + * @date 2023/10/13 15:48 + * @description + */ +@RestController +public class ServiceGithubResourceImpl implements ServiceGithubResource{ + + @Resource + private GithubTokenService githubTokenService; + + @Resource + private IGithubService githubService; + + @Override + public CommonResult getAccessToken(String userId, GitHubTokenType tokenType) { + return CommonResult.success(githubTokenService.getAccessToken(userId, tokenType != null ? tokenType : GitHubTokenType.GITHUB_APP)); + } + + @Override + public CommonResult getGithubBranch(String accessToken, String projectName, String branch) { + return CommonResult.success(githubService.getBranch(accessToken, projectName, branch)); + } + + @Override + public CommonResult getGithubTag(String accessToken, String projectName, String tag) { + return CommonResult.success(githubService.getTag(accessToken, projectName, tag)); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResource.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResource.java new file mode 100644 index 0000000..e078368 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResource.java @@ -0,0 +1,31 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@Tag(name = "服务-oauth相关") +@RequestMapping("/service/oauth") +public interface ServiceOauthResource { + + @Operation(summary = "获取git代码库accessToken信息") + @GetMapping("/git/{userId}") + CommonResult gitGet( + @Parameter(description = "用户ID", required = true) + @PathVariable String userId); + + @Operation(summary = "获取tgit代码库accessToken信息") + @GetMapping("/tgit/{userId}") + CommonResult tGitGet( + @Parameter(description = "用户ID", required = true) + @PathVariable String userId); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResourceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResourceImpl.java new file mode 100644 index 0000000..d90f312 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceOauthResourceImpl.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import cd.casic.pipeline.scm.service.IGitOauthService; +import cd.casic.pipeline.scm.service.tgit.TGitOauthService; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ServiceOauthResourceImpl implements ServiceOauthResource { + + @Resource + private IGitOauthService gitOauthService; + + @Resource + private TGitOauthService tGitOauthService; + + @Override + public CommonResult gitGet(String userId) { + return CommonResult.success(gitOauthService.getAccessToken(userId)); + } + + @Override + public CommonResult tGitGet(String userId) { + return CommonResult.success(tGitOauthService.getAccessToken(userId)); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResource.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResource.java new file mode 100644 index 0000000..72caae0 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResource.java @@ -0,0 +1,32 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.Repository; +import cd.casic.pipeline.scm.enums.RepositoryType; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Tag(name = "服务-代码库资源") +@RequestMapping("/service/repositories") +public interface ServiceRepositoryResource { + + @Operation(summary = "获取git代码库详情") + @GetMapping("/{projectId}/{repositoryId}") + CommonResult get( + @Parameter(description = "用户ID", required = true) + @PathVariable + String projectId, + @Parameter(description = "代码库哈希ID或代码库名称", required = true) + @PathVariable + String repositoryId, + @Parameter(description = "代码库请求类型", required = true) + RepositoryType repositoryType + ); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResourceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResourceImpl.java new file mode 100644 index 0000000..439aea8 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/ServiceRepositoryResourceImpl.java @@ -0,0 +1,40 @@ +package cd.casic.pipeline.scm.api; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.Repository; +import cd.casic.pipeline.scm.enums.RepositoryType; +import cd.casic.pipeline.scm.service.impl.RepositoryServiceImpl; +import cd.casic.pipeline.scm.utils.RepositoryConfigUtils; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.RestController; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + + +@RestController +public class ServiceRepositoryResourceImpl implements ServiceRepositoryResource { + + @Resource + private RepositoryServiceImpl repositoryService; + + @Override + public CommonResult get(String projectId, String repositoryId, RepositoryType repositoryType) { + if (StringUtils.isBlank(projectId)) { + throw new ServiceException(-1000, "Invalid projectId"); + } + if (StringUtils.isBlank(repositoryId)) { + throw new ServiceException(-1000, "Invalid repositoryHashId"); + } + try { + return CommonResult.success(repositoryService.serviceGet(projectId, RepositoryConfigUtils.buildConfig(URLDecoder.decode(repositoryId, "UTF-8"), repositoryType))); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return CommonResult.error(-1000, "not found"); + } + +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResource.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResource.java new file mode 100644 index 0000000..491ad54 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResource.java @@ -0,0 +1,92 @@ +package cd.casic.pipeline.scm.api.scm; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Tag(name = "Service Code Svn resource") +@RequestMapping("/service/scm/oauth") +public interface ServiceScmOauthResource { + + + @Operation(description = "Get the repo latest revision") + @PostMapping("/latestRevision") + @Parameters({ + @Parameter(name = "projectName", description = "项目名称", required = true), + @Parameter(name = "url", description = "仓库地址", required = true), + @Parameter(name = "type", description = "仓库类型", required = true), + @Parameter(name = "branchName", description = "branch name", required = false), + @Parameter(name = "additionalPath", description = "SVN additional path", required = false), + @Parameter(name = "privateKey", description = "privateKey", required = false), + @Parameter(name = "passPhrase", description = "passPhrase", required = false), + @Parameter(name = "token", description = "token", required = false), + @Parameter(name = "region", description = "仓库区域前缀(只有svn用到)", required = false), + @Parameter(name = "userName", description = "仓库对应的用户名", required = false) + }) + CommonResult getLatestRevision( + @RequestParam + String projectName, + @RequestParam + String url, + @RequestParam + ScmType type, + @RequestParam + String branchName, + @RequestParam + String additionalPath, + @RequestParam + String privateKey, + @RequestParam + String passPhrase, + @RequestParam + String token, + @RequestParam + CodeSvnRegion region, + @RequestParam + String userName + ); + + @PostMapping("/addWebhook") + @Parameters({ + @Parameter(name = "projectName", description = "项目名称", required = true), + @Parameter(name = "url", description = "仓库地址", required = true), + @Parameter(name = "type", description = "仓库类型", required = true), + @Parameter(name = "privateKey", description = "privateKey", required = true), + @Parameter(name = "passPhrase", description = "passPhrase", required = false), + @Parameter(name = "token", description = "token", required = false), + @Parameter(name = "region", description = "仓库区域前缀(只有svn用到)", required = false), + @Parameter(name = "userName", description = "仓库对应的用户名", required = true), + @Parameter(name = "event", description = "事件类型", required = false) + }) + CommonResult addWebhook( + @RequestParam + String projectName, + @RequestParam + String url, + @RequestParam + ScmType type, + @RequestParam + String privateKey, + @RequestParam + String passPhrase, + @RequestParam + String token, + @RequestParam + CodeSvnRegion region, + @RequestParam + String userName, + @RequestParam + String event + ); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResourceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResourceImpl.java new file mode 100644 index 0000000..89f426a --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmOauthResourceImpl.java @@ -0,0 +1,36 @@ +package cd.casic.pipeline.scm.api.scm; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import cd.casic.pipeline.scm.service.scm.IScmOauthService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@Slf4j +public class ServiceScmOauthResourceImpl implements ServiceScmOauthResource{ + + @Resource + private IScmOauthService scmOauthService; + + @Override + public CommonResult getLatestRevision(String projectName, String url, ScmType type, String branchName, String additionalPath, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName) { + log.info("getLatestRevision|(projectName={}, url={}, type={}, branch={}, " + + "additionalPath={}, region={}, username={}", projectName, url, type, branchName, additionalPath, region, userName); + return CommonResult.success(scmOauthService.getLatestRevision( + projectName, url, type, branchName, privateKey, + passPhrase, token, region, userName)); + } + + @Override + public CommonResult addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName, String event) { + log.info("addWebHook|(projectName={}, url={}, type={}, username={}, event={})", projectName, url, type, userName, event); + scmOauthService.addWebhook(projectName, url, type, privateKey, passPhrase, token, region, userName, event); + return CommonResult.success(true); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResource.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResource.java new file mode 100644 index 0000000..19703f5 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResource.java @@ -0,0 +1,92 @@ +package cd.casic.pipeline.scm.api.scm; + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + + +@RestController +@Tag(name = "仓库分支、tag、hook相关") +@RequestMapping("/service/scm") +public interface ServiceScmResource { + + @Operation(summary = "Get the repo latest revision") + @GetMapping("/latestRevision") + @Parameters({ + @Parameter(name = "projectName", description = "项目名称", required = true), + @Parameter(name = "url", description = "仓库地址", required = true), + @Parameter(name = "type", description = "仓库类型", required = true), + @Parameter(name = "branchName", description = "branch name", required = false), + @Parameter(name = "additionalPath", description = "SVN additional path", required = false), + @Parameter(name = "privateKey", description = "privateKey", required = false), + @Parameter(name = "passPhrase", description = "passPhrase", required = false), + @Parameter(name = "token", description = "token", required = false), + @Parameter(name = "region", description = "仓库区域前缀(只有svn用到)", required = false), + @Parameter(name = "userName", description = "仓库对应的用户名", required = true) + }) + CommonResult getLatestRevision( + @RequestParam + String projectName, + @RequestParam + String url, + @RequestParam + ScmType type, + @RequestParam + String branchName, + @RequestParam + String additionalPath, + @RequestParam + String privateKey, + @RequestParam + String passPhrase, + @RequestParam + String token, + @RequestParam + CodeSvnRegion region, + @RequestParam + String userName + ); + + @Operation(summary = "添加Git或者Gitlab WEB hook") + @PostMapping("/addWebhook") + @Parameters({ + @Parameter(name = "projectName", description = "项目名称", required = true), + @Parameter(name = "url", description = "仓库地址", required = true), + @Parameter(name = "type", description = "仓库类型", required = true), + @Parameter(name = "privateKey", description = "privateKey", required = true), + @Parameter(name = "passPhrase", description = "passPhrase", required = false), + @Parameter(name = "token", description = "token", required = true), + @Parameter(name = "region", description = "仓库区域前缀(只有svn用到)", required = false), + @Parameter(name = "userName", description = "仓库对应的用户名", required = true), + @Parameter(name = "event", description = "事件类型", required = false), + @Parameter(name = "hookUrl", description = "回调Url", required = false) + }) + CommonResult addWebhook( + @RequestParam + String projectName, + @RequestParam + String url, + @RequestParam + ScmType type, + @RequestParam + String privateKey, + @RequestParam + String passPhrase, + @RequestParam + String token, + @RequestParam + CodeSvnRegion region, + @RequestParam + String userName, + @RequestParam + String event, + @RequestParam + String hookUrl + ); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResourceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResourceImpl.java new file mode 100644 index 0000000..df5009e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/api/scm/ServiceScmResourceImpl.java @@ -0,0 +1,33 @@ +package cd.casic.pipeline.scm.api.scm; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import cd.casic.pipeline.scm.service.scm.IScmService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@Slf4j +public class ServiceScmResourceImpl implements ServiceScmResource{ + + @Resource + private IScmService scmService; + + @Override + public CommonResult getLatestRevision(String projectName, String url, ScmType type, String branchName, String additionalPath, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName) { + log.info("getLatestRevision|{}|{}|{}|{}|{}|{}|username={}", projectName, url, type, branchName, additionalPath, region, userName); + return CommonResult.success(scmService.getLatestRevision(projectName, url, type, branchName, privateKey, passPhrase, token, region, userName)); + } + + @Override + public CommonResult addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName, String event, String hookUrl) { + log.info("addWebhook|{}|{}|{}|{}|{}|{}|{}", projectName, url, type, userName, region, event, hookUrl); + scmService.addWebhook(projectName, url, type, privateKey, passPhrase, token, region, userName, event, hookUrl); + return CommonResult.success(true); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/GitConfig.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/GitConfig.java new file mode 100644 index 0000000..f0f39ab --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/GitConfig.java @@ -0,0 +1,73 @@ +package cd.casic.pipeline.scm.config; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +/** + * @author mianbin + * @description Git通用配置 + * @date 2024/10/18 14:45 + */ +@Configuration +@ConditionalOnWebApplication +@AutoConfigureOrder(value = Ordered.LOWEST_PRECEDENCE) +public class GitConfig { + + public final String gitlabUrl = ""; + + public final String gitlabApiUrl = ""; + + public final String gitlabHookUrl = ""; + + public final String gitUrl = ""; + + public final String gitApiUrl = ""; + + public final String clientId = ""; + + public final String clientSecret = ""; + + public final String redirectUrl = ""; + + public final String gitHookUrl = ""; + + public final String callbackUrl = ""; + + public final String hookLockToken = ""; + + public final String signSecret = ""; + + public final String githubClientId = ""; + + public final String oauthAppClientId = ""; + + public final String githubClientSecret = ""; + + public final String oauthAppClientSecret = ""; + + public final String githubWebhookUrl = ""; + + public final String githubCallbackUrl = ""; + + public final String githubRedirectUrl = ""; + + public final String githubAppUrl = ""; + + public final String tGitUrl = ""; + + public final String tGitApiUrl = ""; + + public final String tGitClientId = ""; + + public final String tGitClientSecret = ""; + + public final String tGitWebhookUrl = ""; + + public final String frontendSampleProjectUrl = ""; + + public final String tGitHookUrl = ""; + + public final String tGitHookSecret = ""; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/P4Config.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/P4Config.java new file mode 100644 index 0000000..4e456b7 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/P4Config.java @@ -0,0 +1,19 @@ +package cd.casic.pipeline.scm.config; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +/** + * @author mianbin + * @description P4配置 + * @date 2023/1/16 10:56 + */ +@Configuration +@ConditionalOnWebApplication +@AutoConfigureOrder(value = Ordered.LOWEST_PRECEDENCE) +public class P4Config { + + public String p4HookUrl = ""; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/SVNConfig.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/SVNConfig.java new file mode 100644 index 0000000..adc0e3d --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/config/SVNConfig.java @@ -0,0 +1,25 @@ +package cd.casic.pipeline.scm.config; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +/** + * @author mianbin + * @description SVN通用配置 + * @date 2022/10/18 14:45 + */ +@Configuration +@ConditionalOnWebApplication +@AutoConfigureOrder(value = Ordered.LOWEST_PRECEDENCE) +public class SVNConfig { + + public final String apiUrl = ""; + + public final String apiKey = ""; + + public final String webhookApiUrl = ""; + + public final String svnHookUrl = ""; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitTokenMapper.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitTokenMapper.java new file mode 100644 index 0000000..631fc96 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitTokenMapper.java @@ -0,0 +1,14 @@ +package cd.casic.pipeline.scm.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.scm.dal.dto.RepositoryGitToken; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author by mianbin + * @Classname RepositoryGitTokenMapper + * @Date 2025/3/21 15:19 + */ +@Mapper +public interface RepositoryGitTokenMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitlabTokenMapper.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitlabTokenMapper.java new file mode 100644 index 0000000..6991f65 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryGitlabTokenMapper.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.scm.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.scm.dal.dto.RepositoryGitlabToken; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author by mianbin + * @Classname RepositoryGitlabTokenmapper + * @Description TODO + * @Date 2025/3/21 15:18 + */ +@Mapper +public interface RepositoryGitlabTokenMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryRecordMapper.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryRecordMapper.java new file mode 100644 index 0000000..f8c3046 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryRecordMapper.java @@ -0,0 +1,14 @@ +package cd.casic.pipeline.scm.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.scm.dal.dto.RepositoryRecord; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author by mianbin + * @Classname RepositoryRecordMapper + * @Date 2025/3/21 15:20 + */ +@Mapper +public interface RepositoryRecordMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryTGitTokenMapper.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryTGitTokenMapper.java new file mode 100644 index 0000000..0abe8b8 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dao/RepositoryTGitTokenMapper.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline.scm.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.scm.dal.dto.RepositoryTGitToken; + +/** + * @author by mianbin + * @Classname RepositoryTGitToken + * @Description TODO + * @Date 2025/3/21 15:20 + */ +public interface RepositoryTGitTokenMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitToken.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitToken.java new file mode 100644 index 0000000..49b90f1 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitToken.java @@ -0,0 +1,52 @@ +package cd.casic.pipeline.scm.dal.dto; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * @author mianbin + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "repository_git_token", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class RepositoryGitToken extends BaseDO { + + /** + * 主键ID + */ + private Long id; + + /** + * 用户ID + */ + private String userId; + + /** + * 权限Token + */ + private String accessToken; + + /** + * 刷新Token + */ + private String refreshToken; + + /** + * token类型 + */ + private String tokenType; + + /** + * 过期时间 + */ + private Long expiresIn; + +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitlabToken.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitlabToken.java new file mode 100644 index 0000000..ed3ca12 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryGitlabToken.java @@ -0,0 +1,33 @@ +package cd.casic.pipeline.scm.dal.dto; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + + +/** + * @author mianbin + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "repository_git_token", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class RepositoryGitlabToken extends BaseDO { + private Long id; + + private String userId; + + private String accessToken; + + private String tokenType; + + private String scope; + + private String type; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryRecord.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryRecord.java new file mode 100644 index 0000000..6260338 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryRecord.java @@ -0,0 +1,44 @@ +package cd.casic.pipeline.scm.dal.dto; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + + +/** + * @author mianbin + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "repository_record", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class RepositoryRecord extends BaseDO { + private Long id; + + private String projectId; + + private String userId; + + private String aliasName; + + private String url; + + private String type; + + private String repositoryHashId; + + public RepositoryRecord(String projectId, String userId, String aliasName, String url, String type, String repositoryHashId) { + this.projectId = projectId; + this.userId = userId; + this.aliasName = aliasName; + this.url = url; + this.type = type; + this.repositoryHashId = repositoryHashId; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryTGitToken.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryTGitToken.java new file mode 100644 index 0000000..4c83ba0 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/dto/RepositoryTGitToken.java @@ -0,0 +1,40 @@ +package cd.casic.pipeline.scm.dal.dto; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author mianbin + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class RepositoryTGitToken extends BaseDO { + + private Long id; + + private String userId; + + private String accessToken; + + private String refreshToken; + + private String tokenType; + + private Long expiresIn; + + private String oauthUserId; + + public RepositoryTGitToken(String userId, String accessToken, String refreshToken, String tokenType, Long expiresIn, String oauthUserId) { + this.userId = userId; + this.accessToken = accessToken; + this.refreshToken = refreshToken; + this.tokenType = tokenType; + this.expiresIn = expiresIn; + this.oauthUserId = oauthUserId; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitRepository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitRepository.java new file mode 100644 index 0000000..2379f7d --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitRepository.java @@ -0,0 +1,38 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import cd.casic.pipeline.scm.enums.RepoAuthType; +import cd.casic.pipeline.scm.utils.GitUtils; +import lombok.Data; + +@Data +public class CodeGitRepository extends Repository { + private RepoAuthType authType; + + private Long gitProjectId; + + public static final String CLASS_TYPE = "codeGit"; + + @Override + public String getStartPrefix() { + if (authType == RepoAuthType.SSH) { + return "git@"; + } else if (authType == RepoAuthType.OAUTH) { + return "http://"; + } else if (authType == RepoAuthType.HTTP) { + return "http://"; + } else if (authType == RepoAuthType.HTTPS) { + return "https://"; + } else { + return "git@"; + } + } + + @Override + public Boolean isLegal() { + if (authType == RepoAuthType.HTTP || authType == RepoAuthType.OAUTH || authType == RepoAuthType.HTTPS) { + return GitUtils.isLegalHttpUrl(url); + } else { + return GitUtils.isLegalSshUrl(url); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitlabRepository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitlabRepository.java new file mode 100644 index 0000000..a192c6d --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeGitlabRepository.java @@ -0,0 +1,39 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import cd.casic.pipeline.scm.enums.RepoAuthType; +import cd.casic.pipeline.scm.utils.GitUtils; +import lombok.Data; + +@Data +public class CodeGitlabRepository extends Repository { + + private RepoAuthType authType; + + private Long gitProjectId; + + public static final String CLASS_TYPE = "codeGitLab"; + + @Override + public String getStartPrefix() { + if (authType == RepoAuthType.SSH) { + return "git@"; + } else if (authType == RepoAuthType.OAUTH) { + return "http://"; + } else if (authType == RepoAuthType.HTTP) { + return "http://"; + } else if (authType == RepoAuthType.HTTPS) { + return "https://"; + } else { + return "git@"; + } + } + + @Override + public Boolean isLegal() { + if (authType == RepoAuthType.HTTP || authType == RepoAuthType.OAUTH || authType == RepoAuthType.HTTPS) { + return GitUtils.isLegalHttpUrl(url); + } else { + return GitUtils.isLegalSshUrl(url); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeP4Repository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeP4Repository.java new file mode 100644 index 0000000..4bcaa39 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeP4Repository.java @@ -0,0 +1,17 @@ +package cd.casic.pipeline.scm.dal.pojo; + + +public class CodeP4Repository extends Repository { + + public static final String CLASS_TYPE = "codeP4"; + + @Override + public String getStartPrefix() { + return ""; + } + + @Override + public Boolean isLegal() { + return true; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeSvnRepository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeSvnRepository.java new file mode 100644 index 0000000..6035535 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeSvnRepository.java @@ -0,0 +1,48 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import lombok.Data; + + +@Data +public class CodeSvnRepository extends Repository { + private CodeSvnRegion region; + + private String svnType; + + public static final String CLASS_TYPE = "codeSvn"; + public static final String SVN_TYPE_HTTP = "http"; + public static final String SVN_TYPE_SSH = "ssh"; + + @Override + public String getStartPrefix() { + return "svn+ssh://"; + } + + @Override + public Boolean isLegal() { + if (svnType.equals(SVN_TYPE_HTTP)) { + return url.startsWith("http://") || url.startsWith("https://") || url.startsWith("svn://"); + } + return url.startsWith(getStartPrefix()); + } + + @Override + public String getFormatURL() { + String fixUrl = url; + if (fixUrl.startsWith("svn+ssh://")) { + String[] split = fixUrl.split("://"); + if (split.length == 2) { + int index = split[1].indexOf("@"); + String suffix; + if (index >= 0) { + suffix = split[1].substring(index + 1); + } else { + suffix = split[1]; + } + fixUrl = split[0] + "://" + suffix; + } + } + return fixUrl; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeTGitRepository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeTGitRepository.java new file mode 100644 index 0000000..333106e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/CodeTGitRepository.java @@ -0,0 +1,41 @@ +package cd.casic.pipeline.scm.dal.pojo; + + +import cd.casic.pipeline.scm.enums.RepoAuthType; +import cd.casic.pipeline.scm.utils.GitUtils; +import lombok.Data; + + +@Data +public class CodeTGitRepository extends Repository { + + private RepoAuthType authType; + + private Long gitProjectId; + + public static final String CLASS_TYPE = "codeTGit"; + + @Override + public String getStartPrefix() { + if (authType == RepoAuthType.SSH) { + return "git@"; + } else if (authType == RepoAuthType.OAUTH) { + return "http://"; + } else if (authType == RepoAuthType.HTTP) { + return "http://"; + } else if (authType == RepoAuthType.HTTPS) { + return "https://"; + } else { + return "git@"; + } + } + + @Override + public Boolean isLegal() { + if (authType == RepoAuthType.HTTP || authType == RepoAuthType.OAUTH || authType == RepoAuthType.HTTPS) { + return GitUtils.isLegalHttpUrl(url); + } else { + return GitUtils.isLegalSshUrl(url); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Credential.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Credential.java new file mode 100644 index 0000000..860c6a7 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Credential.java @@ -0,0 +1,17 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Credential { + + private String username; + + private String privateKey; // password or private key + + private String passPhrase; // passphrase for ssh private key +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/GithubRepository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/GithubRepository.java new file mode 100644 index 0000000..a0ebe0d --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/GithubRepository.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.scm.dal.pojo; + + +/** + * @author mianbin + * @Classname GithubRepository + * @Description github 在线测试 + * @Date 2022/10/18 14:45 + */ +public class GithubRepository extends Repository { + + public static final String CLASS_TYPE = "github"; + + @Override + public String getStartPrefix() { + return "https://github.com/"; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/IScm.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/IScm.java new file mode 100644 index 0000000..ebfe4b8 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/IScm.java @@ -0,0 +1,10 @@ +package cd.casic.pipeline.scm.dal.pojo; + + + +public interface IScm { + + RevisionInfo getLatestRevision(); + + void addWebhook(String hookUrl); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Repository.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Repository.java new file mode 100644 index 0000000..d0153a8 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/Repository.java @@ -0,0 +1,43 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = CodeSvnRepository.class, name = CodeSvnRepository.CLASS_TYPE), + @JsonSubTypes.Type(value = CodeGitRepository.class, name = CodeGitRepository.CLASS_TYPE), + @JsonSubTypes.Type(value = CodeGitlabRepository.class, name = CodeGitlabRepository.CLASS_TYPE), + @JsonSubTypes.Type(value = GithubRepository.class, name = GithubRepository.CLASS_TYPE), + @JsonSubTypes.Type(value = CodeTGitRepository.class, name = CodeTGitRepository.CLASS_TYPE), + @JsonSubTypes.Type(value = CodeP4Repository.class, name = CodeP4Repository.CLASS_TYPE) +}) +@Schema(description = "代码库模型-多态基类") +public abstract class Repository { + protected String aliasName; + + protected String url; + + protected String credentialId; + + protected String projectName; + + protected String userName; + + protected String projectId; + + protected String repoHashId; + + public abstract String getStartPrefix(); + + public Boolean isLegal() { + return url.startsWith(getStartPrefix()); + } + + public String getFormatURL() { + return url; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/RevisionInfo.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/RevisionInfo.java new file mode 100644 index 0000000..26768bf --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/RevisionInfo.java @@ -0,0 +1,23 @@ +package cd.casic.pipeline.scm.dal.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author mianbin + * @ClassName RevisionInfo + * @date 2023/1/16 10:56 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RevisionInfo { + private String revision; + + private String updatedMessage; + + private String branchName; + + private String authorName; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmFactory.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmFactory.java new file mode 100644 index 0000000..036c64f --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmFactory.java @@ -0,0 +1,77 @@ +package cd.casic.pipeline.scm.dal.pojo; + + +import cd.casic.framework.commons.util.spring.SpringUtils; +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.config.SVNConfig; +import cd.casic.pipeline.scm.dal.pojo.git.GitApi; +import cd.casic.pipeline.scm.dal.pojo.svn.*; +import cd.casic.pipeline.scm.enums.CodeGitWebhookEvent; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ScmFactory { + + private static final GitApi gitApi = new GitApi(); + + public static IScm getScm(String projectName, String url, ScmType type, String branchName, String privateKey, String passPhrase, + String token, CodeSvnRegion region, String userName, String event) { + if (type == ScmType.CODE_SVN) { + if (userName == null) { + log.error("the svn username is null"); + //throw new ServiceException("the svn username is null"); + } + if (privateKey == null) { + log.error("The svn private key is null"); + //throw new ServiceException("The svn private key is null"); + } + SVNConfig svnConfig = SpringUtils.getBean(SVNConfig.class); + return new CodeSvnScmImpl(projectName, branchName, url, userName, privateKey, passPhrase, svnConfig); + } else if (type == ScmType.CODE_GIT) { + if (token == null) { + log.error("The git token is null"); + //throw new ServiceException("The git token is null"); + } + if (event != null && CodeGitWebhookEvent.find(event) == null) { + log.error("The git event is invalid"); + //throw new ServiceException("The git event is invalid"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeGitScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, gitApi, event); + } else if (type == ScmType.CODE_TGIT) { + if (token == null) { + log.error("The git token is null"); + //throw new ServiceException("The git token is null"); + } + if (event != null && CodeGitWebhookEvent.find(event) == null) { + log.error("The git event is invalid"); + //throw new ServiceException("The git event is invalid"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeTGitScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, gitApi, event); + } else if (type == ScmType.CODE_GITLAB) { + if (token == null) { + log.error("The gitlab access token is null"); + //throw new ServiceException("The gitlab access token is null"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeGitlabScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, event); + } else if (type == ScmType.CODE_P4) { + if (passPhrase == null) { + log.error("用户密码为空"); + //throw new ServiceException("用户密码为空"); + } + if (userName == null) { + log.error("用户名为空"); + //throw new ServiceException("用户名为空"); + } + return new CodeP4ScmImpl(projectName, branchName, url, userName, passPhrase, event); + } else { + log.error("Unknown repo(" + type + ")"); + //throw new ServiceException("Unknown repo(" + type + ")"); + } + return null; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmOauthFactory.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmOauthFactory.java new file mode 100644 index 0000000..955b0ba --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/ScmOauthFactory.java @@ -0,0 +1,62 @@ +package cd.casic.pipeline.scm.dal.pojo; + + +import cd.casic.framework.commons.util.spring.SpringUtils; +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.config.SVNConfig; +import cd.casic.pipeline.scm.dal.pojo.git.GitOauthApi; +import cd.casic.pipeline.scm.dal.pojo.svn.CodeGitScmImpl; +import cd.casic.pipeline.scm.dal.pojo.svn.CodeGitlabScmImpl; +import cd.casic.pipeline.scm.dal.pojo.svn.CodeSvnScmImpl; +import cd.casic.pipeline.scm.dal.pojo.svn.CodeTGitScmImpl; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ScmOauthFactory { + + + private static final GitOauthApi gitOauthApi = new GitOauthApi(); + + public static IScm getScm(String projectName, String url, ScmType type, String branchName, String privateKey, + String passPhrase, String token, CodeSvnRegion region, String userName, String event) { + if (type == ScmType.CODE_SVN) { + if (userName == null) { + log.error("the svn username is null"); + //throw new ServiceException("the svn username is null"); + } + if (privateKey == null) { + log.error("The svn private key is null"); + //throw new ServiceException("The svn private key is null"); + } + SVNConfig svnConfig = SpringUtils.getBean(SVNConfig.class); + return new CodeSvnScmImpl(projectName, branchName, url, userName, privateKey, passPhrase, svnConfig); + } else if (type == ScmType.CODE_GIT) { + if (token == null) { + log.error("The git token is null"); + //throw new ServiceException("The git token is null"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeGitScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, gitOauthApi, event); + } else if (type == ScmType.CODE_TGIT) { + if (token == null) { + log.error("The git token is null"); + //throw new ServiceException("The git token is null"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeTGitScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, gitOauthApi, event); + } else if (type == ScmType.CODE_GITLAB) { + if (token == null) { + log.error("The gitlab access token is null"); + //throw new ServiceException("The gitlab access token is null"); + } + GitConfig gitConfig = SpringUtils.getBean(GitConfig.class); + return new CodeGitlabScmImpl(projectName, branchName, url, privateKey, passPhrase, token, gitConfig, event); + } else { + log.error("Unknown repo(" + type + ")"); + //throw new ServiceException("Unknown repo(" + type + ")"); + } + return null; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitApi.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitApi.java new file mode 100644 index 0000000..ac16578 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitApi.java @@ -0,0 +1,10 @@ +package cd.casic.pipeline.scm.dal.pojo.git; + +/** + * @author mianbin + * @Classname GitApi + * @Description TODO + * @Date 2023/1/16 10:56 + */ +public class GitApi { +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitOauthApi.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitOauthApi.java new file mode 100644 index 0000000..67fd0e6 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitOauthApi.java @@ -0,0 +1,9 @@ +package cd.casic.pipeline.scm.dal.pojo.git; + +/** + * @author mianbin + * @date 2023/12/13 14:49 + * @Classname GitOauthApi + */ +public class GitOauthApi extends GitApi{ +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitUserInfo.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitUserInfo.java new file mode 100644 index 0000000..e925acc --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/git/GitUserInfo.java @@ -0,0 +1,29 @@ +package cd.casic.pipeline.scm.dal.pojo.git; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author mianbin + * @ClassName GitUserInfo + * @date 2023/1/16 10:56 + */ +@Schema(description = "git用户信息") +@Data +public class GitUserInfo { + + private Integer id; + + private String email; + + private String username; + + private String webUrl; + + private String name; + + private String state; + + private String avatarUrl; +} + diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubBranch.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubBranch.java new file mode 100644 index 0000000..ba47d0c --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubBranch.java @@ -0,0 +1,14 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Data +@Schema(description = "分支模型") +public class GithubBranch { + @Schema(description = "名称") + private String name; + @Schema(description = "提交") + private GithubCommit commit; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommit.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommit.java new file mode 100644 index 0000000..180819c --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommit.java @@ -0,0 +1,17 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "提交模型") +public class GithubCommit { + @Schema(description = "sha值") + private String sha; + + @Schema(description = "节点id", name = "node_id") + private String nodeId; + + @Schema(description = "提交内容") + private GithubCommitData commit; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitAuthor.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitAuthor.java new file mode 100644 index 0000000..a9a7324 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitAuthor.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "提交者模型") +public class GithubCommitAuthor { + + @Schema(description = "提交者名称") + private String name; + + @Schema(description = "提交时间") + private String date; + + @Schema(description = "提交者email") + private String email; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitData.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitData.java new file mode 100644 index 0000000..2bdd1e2 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubCommitData.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "提交内容模型") +public class GithubCommitData { + + @Schema(description = "提交信息") + private String message; + + @Schema(description = "提交者信息") + private GithubCommitAuthor author; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubObject.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubObject.java new file mode 100644 index 0000000..2c92a58 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubObject.java @@ -0,0 +1,19 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Schema(description = "") +@Data +public class GithubObject { + + @Schema(description = "sha值") + private String sha; + + @Schema(description = "类型") + private String type; + + @Schema(description = "url地址") + private String url; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubTag.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubTag.java new file mode 100644 index 0000000..5269aa4 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubTag.java @@ -0,0 +1,22 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Data +@Schema(description = "获取tag返回模型") +public class GithubTag { + + @Schema(description = "远程调用") + private String ref; + + @Schema(description = "节点id") + private String nodeId; + + @Schema(description = "url地址") + private String url; + + @Schema(description = "tag数据") + private GithubObject tagObject; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubToken.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubToken.java new file mode 100644 index 0000000..c8fb99d --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/github/GithubToken.java @@ -0,0 +1,21 @@ +package cd.casic.pipeline.scm.dal.pojo.github; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GithubToken { + + @Schema(name = "access_token", description = "鉴权token") + private String accessToken; + + @Schema(name = "token_type", description = "token类型") + private String tokenType; + + @Schema(description = "范围") + private String scope; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/oauth/GitToken.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/oauth/GitToken.java new file mode 100644 index 0000000..9ff8565 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/oauth/GitToken.java @@ -0,0 +1,34 @@ +package cd.casic.pipeline.scm.dal.pojo.oauth; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@Schema(description = "Token模型") +@NoArgsConstructor +@AllArgsConstructor +public class GitToken { + + @Schema(description = "鉴权token", name = "access_token") + @JsonProperty("access_token") + private String accessToken = ""; + + @Schema(description = "刷新token", name = "refresh_token") + @JsonProperty("refresh_token") + private String refreshToken = ""; + + @Schema(description = "token类型", name = "token_type") + @JsonProperty("token_type") + private String tokenType = ""; + + @Schema(description = "过期时间", name = "expires_in") + @JsonProperty("expires_in") + private Long expiresIn = 0L; + + @Schema(description = "创建时间") + private Long createTime = 0L; +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitScmImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitScmImpl.java new file mode 100644 index 0000000..f75b6bf --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitScmImpl.java @@ -0,0 +1,44 @@ +package cd.casic.pipeline.scm.dal.pojo.svn; + + +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.dal.pojo.IScm; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.dal.pojo.git.GitApi; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CodeGitScmImpl implements IScm { + private String projectName; + + private String branchName; + + private String url; + + private String privateKey; + + private String passPhrase; + + private String token; + + private GitConfig gitConfig; + + private GitApi gitApi; + + private String event; + + @Override + public RevisionInfo getLatestRevision() { + return null; + } + + @Override + public void addWebhook(String hookUrl) { + + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitlabScmImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitlabScmImpl.java new file mode 100644 index 0000000..048d711 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeGitlabScmImpl.java @@ -0,0 +1,41 @@ +package cd.casic.pipeline.scm.dal.pojo.svn; + + +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.dal.pojo.IScm; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CodeGitlabScmImpl implements IScm { + private String projectName; + + private String branchName; + + private String url; + + private String privateKey; + + private String passPhrase; + + private String token; + + private GitConfig gitConfig; + + private String event; + + @Override + public RevisionInfo getLatestRevision() { + return null; + } + + @Override + public void addWebhook(String hookUrl) { + + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeP4ScmImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeP4ScmImpl.java new file mode 100644 index 0000000..078a3bb --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeP4ScmImpl.java @@ -0,0 +1,36 @@ +package cd.casic.pipeline.scm.dal.pojo.svn; + + +import cd.casic.pipeline.scm.dal.pojo.IScm; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CodeP4ScmImpl implements IScm { + private String projectName; + + private String branchName; + + private String url; + + private String username; + + private String password; + + private String event; + + @Override + public RevisionInfo getLatestRevision() { + return null; + } + + @Override + public void addWebhook(String hookUrl) { + + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeSvnScmImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeSvnScmImpl.java new file mode 100644 index 0000000..3029822 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeSvnScmImpl.java @@ -0,0 +1,38 @@ +package cd.casic.pipeline.scm.dal.pojo.svn; + +import cd.casic.pipeline.scm.config.SVNConfig; +import cd.casic.pipeline.scm.dal.pojo.IScm; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CodeSvnScmImpl implements IScm { + private String projectName; + + private String branchName; + + private String url; + + private String username; + + private String privateKey; + + private String passPhrase; + + private SVNConfig svnConfig; + + @Override + public RevisionInfo getLatestRevision() { + return null; + } + + @Override + public void addWebhook(String hookUrl) { + + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeTGitScmImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeTGitScmImpl.java new file mode 100644 index 0000000..63b1f06 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/dal/pojo/svn/CodeTGitScmImpl.java @@ -0,0 +1,44 @@ +package cd.casic.pipeline.scm.dal.pojo.svn; + + +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.dal.pojo.IScm; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.dal.pojo.git.GitApi; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CodeTGitScmImpl implements IScm { + private String projectName; + + private String branchName; + + private String url; + + private String privateKey; + + private String passPhrase; + + private String token; + + private GitConfig gitConfig; + + private GitApi gitApi; + + private String event; + + @Override + public RevisionInfo getLatestRevision() { + return null; + } + + @Override + public void addWebhook(String hookUrl) { + + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeGitWebhookEvent.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeGitWebhookEvent.java new file mode 100644 index 0000000..f652c01 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeGitWebhookEvent.java @@ -0,0 +1,37 @@ +package cd.casic.pipeline.scm.enums; + + +/** + * @author mianbin + * @Classname CodeGitWebhookEvent + * @date 2025/3/18 14:45 + */ + +public enum CodeGitWebhookEvent { + PUSH_EVENTS("push_events"), + TAG_PUSH_EVENTS("tag_push_events"), + ISSUES_EVENTS("issues_events"), + MERGE_REQUESTS_EVENTS("merge_requests_events"), + NOTE_EVENTS("note_events"), + ENABLE_SSL_VERIFICATION("enable_ssl_verification"), + REVIEW_EVENTS("review_events"); + + private String value; + + CodeGitWebhookEvent(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static CodeGitWebhookEvent find(String event) { + for (CodeGitWebhookEvent it : CodeGitWebhookEvent.values()) { + if (it.value.equals(event)) { + return it; + } + } + return null; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeSvnRegion.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeSvnRegion.java new file mode 100644 index 0000000..5d383d1 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/CodeSvnRegion.java @@ -0,0 +1,36 @@ +package cd.casic.pipeline.scm.enums; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + + +public enum CodeSvnRegion { + TC("tc-svn"), + SH("sh-svn"), + BJ("bj-svn"), + GZ("gz-svn"), + CD("svn-cd1"), + GROUP("group-svn1.group"); + + private String prefix; + + CodeSvnRegion(String prefix){ + this.prefix = prefix; + } + + public String getPrefix() { + return prefix; + } + + private static final Map map = Arrays.stream(values()).collect(Collectors.toMap(CodeSvnRegion::getPrefix, Enum::toString)); + + public CodeSvnRegion getRegion(String value){ + for (CodeSvnRegion region : values()) { + if (value.startsWith(region.prefix)){ + return region; + } + } + return TC; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/GitHubTokenType.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/GitHubTokenType.java new file mode 100644 index 0000000..352eebf --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/GitHubTokenType.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.scm.enums; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "github token 类型") +public enum GitHubTokenType { + GITHUB_APP("ghu_"), + OAUTH_APP("gho_"); + + private String prefix; + + GitHubTokenType(String prefix){ + this.prefix = prefix; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepoAuthType.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepoAuthType.java new file mode 100644 index 0000000..43f49fa --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepoAuthType.java @@ -0,0 +1,22 @@ +package cd.casic.pipeline.scm.enums; + + +public enum RepoAuthType { + SSH, + HTTP, + HTTPS, + OAUTH; + + public RepoAuthType parse(String type){ + switch (type){ + case "HTTP": + return HTTP; + case "HTTPS": + return HTTPS; + case "OAUTH": + return OAUTH; + default: + return SSH; + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryConfig.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryConfig.java new file mode 100644 index 0000000..6ab1a47 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryConfig.java @@ -0,0 +1,54 @@ +package cd.casic.pipeline.scm.enums; + +import cd.casic.framework.commons.exception.ErrorCode; +import cd.casic.framework.commons.exception.ServiceException; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class RepositoryConfig { + + private String repositoryHashId; + + private String repositoryName; + + private RepositoryType repositoryType; + + public String getRepositoryId() { + if (repositoryType == RepositoryType.ID) { + if (StringUtils.isEmpty(repositoryHashId)) { + throw new ServiceException(new ErrorCode(-1000, "代码库HashId为空")); + } else { + return repositoryHashId; + } + } else if (repositoryType == RepositoryType.NAME) { + if (StringUtils.isEmpty(repositoryName)) { + throw new ServiceException(new ErrorCode(-1000, "代码库名为空")); + } else { + return repositoryName; + } + } + return null; + } + + public String getURLEncodeRepositoryId() { + try { + return URLEncoder.encode(getRepositoryId(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public String toString() { + return "[repositoryHashId=" + repositoryHashId + ", repositoryName=" + repositoryName + ", repositoryType=" + repositoryType + "]"; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryType.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryType.java new file mode 100644 index 0000000..c6678f5 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryType.java @@ -0,0 +1,16 @@ +package cd.casic.pipeline.scm.enums; + +import org.apache.commons.lang3.StringUtils; + + +public enum RepositoryType { + ID, + NAME; + + public static RepositoryType parseType(String type) { + if (StringUtils.isBlank(type) || StringUtils.isEmpty(type)) { + return ID; + } + return RepositoryType.valueOf(type); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryTypeNew.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryTypeNew.java new file mode 100644 index 0000000..1ec07cb --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RepositoryTypeNew.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.scm.enums; + +import org.apache.commons.lang3.StringUtils; + + +public enum RepositoryTypeNew { + ID, + NAME, + URL; + + public static RepositoryTypeNew parseType(String type) { + if (StringUtils.isBlank(type)) { + return ID; + } + + return valueOf(type); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RequestChannelTypeEnum.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RequestChannelTypeEnum.java new file mode 100644 index 0000000..6411244 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/RequestChannelTypeEnum.java @@ -0,0 +1,10 @@ +package cd.casic.pipeline.scm.enums; + + +public enum RequestChannelTypeEnum { + USER, + SERVICE, + BUILD, + OP, + OPEN +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/ScmType.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/ScmType.java new file mode 100644 index 0000000..e06582f --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/ScmType.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.scm.enums; + + +public enum ScmType { + CODE_SVN, + CODE_GIT, + CODE_GITLAB, + GITHUB, + CODE_TGIT, + CODE_P4; + + public static Short parse(ScmType type) { + switch (type) { + case CODE_SVN: + return 1; + case CODE_GIT: + return 2; + case CODE_GITLAB: + return 3; + case GITHUB: + return 4; + case CODE_TGIT: + return 5; + case CODE_P4: + return 6; + default: + return 0; + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/TokenTypeEnum.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/TokenTypeEnum.java new file mode 100644 index 0000000..f409ccf --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/enums/TokenTypeEnum.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline.scm.enums; + + +public enum TokenTypeEnum { + OAUTH(0), + PRIVATE_KEY(1); + + private Integer type; + + TokenTypeEnum(Integer type) { + this.type = type; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/CodeRepositoryServiceRegistrar.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/CodeRepositoryServiceRegistrar.java new file mode 100644 index 0000000..fdeea4c --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/CodeRepositoryServiceRegistrar.java @@ -0,0 +1,60 @@ +package cd.casic.pipeline.scm.service; + + +import cd.casic.pipeline.scm.enums.ScmType; +import cd.casic.pipeline.scm.dal.pojo.*; +import cd.casic.pipeline.scm.service.code.CodeRepositoryService; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author by mianbin + * @Classname CodeRepositoryServiceRegistrar + * @Description TODO + * @Date 2025/3/21 10:22 + */ +public class CodeRepositoryServiceRegistrar { + private static ConcurrentHashMap> repositoryServiceMap = new ConcurrentHashMap<>(); + + public static CodeRepositoryService getServiceByScmType(String scmType) { + CodeRepositoryService repositoryService; + ScmType type = ScmType.valueOf(scmType); + if (type == ScmType.CODE_SVN) { + repositoryService = getService(CodeSvnRepository.class); + } + else if (type == ScmType.CODE_GIT) { + repositoryService = getService(CodeGitRepository.class); + } + else if (type == ScmType.CODE_TGIT) { + repositoryService = getService(CodeTGitRepository.class); + } + else if (type == ScmType.CODE_GITLAB) { + repositoryService = getService(CodeGitlabRepository.class); + } + else if (type == ScmType.GITHUB) { + repositoryService = getService(GithubRepository.class); + } + else if (type == ScmType.CODE_P4) { + repositoryService = getService(CodeP4Repository.class); + } + else { + throw new IllegalArgumentException("Unknown repository type"); + } + return repositoryService; + } + + /** + * 根据类型读取指定[CodeRepositoryService]代码库业务处理器 + */ + private static CodeRepositoryService getService(Class type) { + if (type != null) { + CodeRepositoryService repositoryService = repositoryServiceMap.get(type.getName()); + if (repositoryService == null) { + throw new IllegalArgumentException(type.getName() + "handler is not found"); + } + return (CodeRepositoryService) repositoryService; + } else { + throw new IllegalArgumentException("Unknown repository type"); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/IGitOauthService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/IGitOauthService.java new file mode 100644 index 0000000..d8a1c9e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/IGitOauthService.java @@ -0,0 +1,11 @@ +package cd.casic.pipeline.scm.service; + + +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; + +public interface IGitOauthService { + + GitToken getAccessToken(String userId); + + int saveAccessToken(String userId, GitToken token); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/code/CodeRepositoryService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/code/CodeRepositoryService.java new file mode 100644 index 0000000..a4fb06e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/code/CodeRepositoryService.java @@ -0,0 +1,10 @@ +package cd.casic.pipeline.scm.service.code; + + +import cd.casic.pipeline.scm.dal.dto.RepositoryRecord; +import cd.casic.pipeline.scm.dal.pojo.Repository; + +public interface CodeRepositoryService { + + Repository compose(RepositoryRecord repository); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubService.java new file mode 100644 index 0000000..e0380d5 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubService.java @@ -0,0 +1,157 @@ +package cd.casic.pipeline.scm.service.github; + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.util.http.OkhttpUtils; +import cd.casic.framework.commons.util.retry.RetryUtils; +import cd.casic.pipeline.commons.constant.CommonMessageCode; +import cd.casic.pipeline.scm.dal.pojo.github.GithubBranch; +import cd.casic.pipeline.scm.dal.pojo.github.GithubTag; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.stereotype.Service; + +import java.util.Objects; + + +@Service +@Slf4j +public class GithubService implements IGithubService { + + private static final int HTTP_200 = 200; + private static final int HTTP_400 = 400; + private static final int HTTP_401 = 401; + private static final int HTTP_402 = 402; + private static final int HTTP_403 = 403; + private static final int HTTP_404 = 404; + private static final int HTTP_405 = 405; + private static final int HTTP_422 = 422; + private static final int HTTP_500 = 500; + + private static final Long SLEEP_MILLS_FOR_RETRY_500 = 500L; + + private static final String GITHUB_API_URL = "https://api.github.com"; + + private static final String OPERATION_GET_BRANCH = "OperationGetBranch"; + + private static final String OPERATION_GET_TAG = "OperationGetTag"; + + @Resource + private ObjectMapper objectMapper; + + @Override + public GithubBranch getBranch(String token, String projectName, String branch) { + log.info("getBranch| {} - {}", projectName, branch); + + return RetryUtils.execute(new RetryUtils.Action() { + @Override + public GithubBranch execute() { + String sBranch = branch != null ? branch : "master"; + String path = "repos/" + projectName + "/branches/" + sBranch; + Request request = buildGet(token, path); + String operation = getMessageByLocale(OPERATION_GET_BRANCH, null); + String body = getBody(operation, request); + try { + return objectMapper.readValue(body, new TypeReference() { + }); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public GithubBranch fail(Throwable e) throws Throwable { + log.warn("BKSystemMonitor|getBranch fail| e=" + e.getMessage(), e); + throw e; + } + + } , 1, SLEEP_MILLS_FOR_RETRY_500); + } + + @Override + public GithubTag getTag(String token, String projectName, String tag) { + log.info("getTag| {} - {}", projectName, tag); + return RetryUtils.execute(new RetryUtils.Action() { + @Override + public GithubTag execute() { + String path = "repos/" + projectName + "/git/refs/tags/" + tag; + Request request = buildGet(token, path); + String operation = getMessageByLocale(OPERATION_GET_TAG, null); + String body = getBody(operation, request); + try { + return objectMapper.readValue(body, new TypeReference() { + }); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public GithubTag fail(Throwable e) throws Throwable { + log.warn("BKSystemMonitor|getTag fail| e=" + e.getMessage(), e); + throw e; + } + }, 1, SLEEP_MILLS_FOR_RETRY_500); + } + + private Request buildGet(String token, String path) { + return request(token, path) + .get() + .build(); + } + + private Request.Builder request(String token, String path) { + return new Request.Builder() + .url(GITHUB_API_URL + "/" + path) + .header("Authorization", "token " + token) + .header("Accept", " application/vnd.github.antiope-preview+json"); + } + + + @SneakyThrows + private String getBody(String operation, Request request) { + Response response = OkhttpUtils.doHttp(request); + int code = response.code(); + String message = response.message(); + String body = Objects.requireNonNull(response.body()).string(); + if (log.isDebugEnabled()) { + log.debug("getBody operation({}). response code({}) message({}) body({})", operation, code, message, body); + } + if (!response.isSuccessful()) { + handException(operation, code); + } + return body; + } + + private void handException(String operation, int code) { + String msg; + switch (code) { + case HTTP_400: + msg = getMessageByLocale(CommonMessageCode.PARAM_ERROR, null); + break; + case HTTP_401: + msg = getMessageByLocale(CommonMessageCode.AUTH_FAIL, new String[]{"GitHub token"}); + break; + case HTTP_403: + msg = getMessageByLocale(CommonMessageCode.ACCOUNT_NO_OPERATION_PERMISSIONS, new String[]{operation}); + break; + case HTTP_404: + msg = getMessageByLocale(CommonMessageCode.REPO_NOT_EXIST_OR_NO_OPERATION_PERMISSION, new String[]{"GitHub", operation}); + default: + msg = "GitHub platform" + operation + "fail"; + break; + } + throw new ServiceException(-1000 , msg); + } + + private String getMessageByLocale(String messageCode, String[] params) { + return ""; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenService.java new file mode 100644 index 0000000..8cbf727 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenService.java @@ -0,0 +1,10 @@ +package cd.casic.pipeline.scm.service.github; + + +import cd.casic.pipeline.scm.dal.pojo.github.GithubToken; +import cd.casic.pipeline.scm.enums.GitHubTokenType; + +public interface GithubTokenService { + + GithubToken getAccessToken(String userId, GitHubTokenType tokenType); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenServiceImpl.java new file mode 100644 index 0000000..cfadf3f --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/GithubTokenServiceImpl.java @@ -0,0 +1,32 @@ +package cd.casic.pipeline.scm.service.github; + + +import cd.casic.framework.commons.util.encrypt.AESUtil; +import cd.casic.pipeline.scm.dal.dao.RepositoryGitlabTokenMapper; +import cd.casic.pipeline.scm.dal.dto.RepositoryGitlabToken; +import cd.casic.pipeline.scm.dal.pojo.github.GithubToken; +import cd.casic.pipeline.scm.enums.GitHubTokenType; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class GithubTokenServiceImpl implements GithubTokenService { + + private final String aesKey = ""; + + @Resource + private RepositoryGitlabTokenMapper repositoryGitlabTokenMapper; + + @Override + public GithubToken getAccessToken(String userId, GitHubTokenType tokenType) { + RepositoryGitlabToken gitlabToken = repositoryGitlabTokenMapper.selectOne(RepositoryGitlabToken::getUserId, userId, RepositoryGitlabToken::getType, tokenType.name()); + if (gitlabToken == null) { + return null; + } + log.info("github aesKey:" + aesKey); + return new GithubToken(AESUtil.decrypt(aesKey, gitlabToken.getAccessToken()), gitlabToken.getTokenType(), gitlabToken.getScope()); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/IGithubService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/IGithubService.java new file mode 100644 index 0000000..13b2a9f --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/github/IGithubService.java @@ -0,0 +1,12 @@ +package cd.casic.pipeline.scm.service.github; + + +import cd.casic.pipeline.scm.dal.pojo.github.GithubBranch; +import cd.casic.pipeline.scm.dal.pojo.github.GithubTag; + +public interface IGithubService { + + GithubBranch getBranch(String token, String projectName, String branch); + + GithubTag getTag(String token, String projectName, String tag); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/GitOauthServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/GitOauthServiceImpl.java new file mode 100644 index 0000000..f906589 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/GitOauthServiceImpl.java @@ -0,0 +1,100 @@ +package cd.casic.pipeline.scm.service.impl; + + +import cd.casic.framework.commons.util.encrypt.AESUtil; +import cd.casic.pipeline.scm.dal.dao.RepositoryGitTokenMapper; +import cd.casic.pipeline.scm.dal.dto.RepositoryGitToken; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import cd.casic.pipeline.scm.service.IGitOauthService; +import cd.casic.pipeline.scm.service.scm.IGitService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.redisson.RedissonRedLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import java.time.ZoneId; + +@Service +@Slf4j +public class GitOauthServiceImpl implements IGitOauthService { + + private static final String aesKey = ""; + + @Resource + private IGitService gitService; + + @Resource + private RepositoryGitTokenMapper repositoryGitTokenMapper; + + @Resource + private RedissonClient redissonClient; + + @Override + public GitToken getAccessToken(String userId) { + GitToken accessToken = doGetAccessToken(userId); + if (accessToken == null) { + return null; + } + + if (isTokenExpire(accessToken)) { + log.info("try to refresh the git token of user({})", userId); + RLock rLock = redissonClient.getLock("OAUTH_REFRESH_TOKEN_" + userId); + RedissonRedLock redisLock = new RedissonRedLock(rLock); + try { + redisLock.lock(); + GitToken newAccessToken = doGetAccessToken(userId); + if (newAccessToken.getExpiresIn() * 1000 <= System.currentTimeMillis() - 1800 * 1000) { + return refreshToken(userId, newAccessToken); + } else { + return newAccessToken; + } + } finally { + redisLock.unlock(); + } + } else { + return accessToken; + } + } + + private GitToken refreshToken(String userId, GitToken gitToken) { + GitToken token = gitService.refreshToken(userId, gitToken); + saveAccessToken(userId, token); + token.setAccessToken(AESUtil.decrypt(aesKey, token.getAccessToken())); + token.setAccessToken(AESUtil.decrypt(aesKey, token.getRefreshToken())); + return token; + } + + @Override + public int saveAccessToken(String userId, GitToken tGitToken) { + tGitToken.setAccessToken(AESUtil.encrypt(aesKey, tGitToken.getAccessToken())); + tGitToken.setRefreshToken(AESUtil.encrypt(aesKey, tGitToken.getRefreshToken())); + RepositoryGitToken repositoryGitToken = new RepositoryGitToken(); + repositoryGitToken.setUserId(userId); + repositoryGitToken.setAccessToken(tGitToken.getAccessToken()); + repositoryGitToken.setRefreshToken(tGitToken.getRefreshToken()); + repositoryGitToken.setTokenType(tGitToken.getTokenType()); + repositoryGitToken.setExpiresIn(tGitToken.getExpiresIn()); + return repositoryGitTokenMapper.insert(repositoryGitToken); + } + + private Boolean isTokenExpire(GitToken accessToken) { + // 提前半个小时刷新token + return (accessToken.getCreateTime() != null ? accessToken.getCreateTime() : 0) + accessToken.getExpiresIn() * 1000 - 1800 * 1000 <= System.currentTimeMillis(); + } + + private GitToken doGetAccessToken(String userId) { + RepositoryGitToken token = repositoryGitTokenMapper.selectOne(RepositoryGitToken::getUserId, userId); + if (token == null) { + return null; + } else { + return new GitToken( + AESUtil.decrypt(aesKey, token.getAccessToken()), + AESUtil.decrypt(aesKey, token.getRefreshToken()), + token.getTokenType(), token.getExpiresIn(), + token.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + ); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/RepositoryServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/RepositoryServiceImpl.java new file mode 100644 index 0000000..63486f4 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/impl/RepositoryServiceImpl.java @@ -0,0 +1,64 @@ +package cd.casic.pipeline.scm.service.impl; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import cd.casic.pipeline.scm.dal.dao.RepositoryRecordMapper; +import cd.casic.pipeline.scm.dal.dto.RepositoryRecord; +import cd.casic.pipeline.scm.dal.pojo.Repository; +import cd.casic.pipeline.scm.enums.RepositoryConfig; +import cd.casic.pipeline.scm.enums.RepositoryType; +import cd.casic.pipeline.scm.service.CodeRepositoryServiceRegistrar; +import cd.casic.pipeline.scm.service.code.CodeRepositoryService; +import cd.casic.pipeline.scm.utils.HashUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class RepositoryServiceImpl { + + @Resource + private RepositoryRecordMapper repositoryRecordMapper; + + + public Repository serviceGet(String projectId, RepositoryConfig repositoryConfig) { + return compose(getRepository(projectId, repositoryConfig)); + } + + private Repository compose(RepositoryRecord repository) { + CodeRepositoryService codeRepositoryService = CodeRepositoryServiceRegistrar.getServiceByScmType(repository.getType()); + return codeRepositoryService.compose(repository); + } + + private RepositoryRecord getRepository(String projectId, RepositoryConfig repositoryConfig) { + log.info("[{}Start to get the repository - ({})]", projectId, repositoryConfig); + if (repositoryConfig.getRepositoryType() == RepositoryType.ID) { + long repositoryId = HashUtil.decodeOtherIdToLong(repositoryConfig.getRepositoryId()); + LambdaQueryWrapper eq = Wrappers.lambdaQuery() + .eq(RepositoryRecord::getId, repositoryId) + .eq(StringUtils.isNoneBlank(projectId), RepositoryRecord::getProjectId, projectId) + .eq(BaseDO::getDeleted, false); + RepositoryRecord repositoryRecord = repositoryRecordMapper.selectOne(eq); + if (repositoryRecord == null) { + throw new ServiceException(-1000, "not found"); + } + return repositoryRecord; + } else if (repositoryConfig.getRepositoryType() == RepositoryType.NAME) { + LambdaQueryWrapper eq = Wrappers.lambdaQuery() + .eq(RepositoryRecord::getAliasName, repositoryConfig.getRepositoryId()) + .eq(RepositoryRecord::getProjectId, projectId) + .eq(BaseDO::getDeleted, false); + RepositoryRecord repositoryRecord = repositoryRecordMapper.selectOne(eq); + if (repositoryRecord == null) { + throw new ServiceException(-1000, "not found"); + } + return repositoryRecord; + } + return null; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/GitServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/GitServiceImpl.java new file mode 100644 index 0000000..b2c7061 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/GitServiceImpl.java @@ -0,0 +1,51 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.framework.commons.util.http.OkhttpUtils; +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.stereotype.Service; + +import java.io.IOException; + +@Service +@Slf4j +public class GitServiceImpl implements IGitService { + + @Resource + private GitConfig gitConfig; + + @Resource + private ObjectMapper objectMapper; + + @Override + public GitToken refreshToken(String userId, GitToken accessToken) { + log.info("Start to refresh the token of user {}", userId); + long startEpoch = System.currentTimeMillis(); + try { + String url = gitConfig.gitUrl + "/oauth/token" + + "?client_id=" + gitConfig.clientId + + "&client_secret=" + gitConfig.clientSecret + + "&grant_type=refresh_token" + + "&refresh_token=" + accessToken.getRefreshToken() + + "&redirect_uri=" + gitConfig.gitHookUrl; + Request request = new Request.Builder() + .url(url) + .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"), "")) + .build(); + Response response = OkhttpUtils.doHttp(request); + ResponseBody body = response.body(); + assert body != null; + return objectMapper.readValue(body.string(), GitToken.class); + } catch (IOException e) { + e.printStackTrace(); + } finally { + log.info("It took {}ms to refresh the token", System.currentTimeMillis() - startEpoch); + } + return null; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IGitService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IGitService.java new file mode 100644 index 0000000..293c3f5 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IGitService.java @@ -0,0 +1,9 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; + +public interface IGitService { + + GitToken refreshToken(String userId, GitToken accessToken); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmOauthService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmOauthService.java new file mode 100644 index 0000000..4d23b10 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmOauthService.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; + +public interface IScmOauthService { + + RevisionInfo getLatestRevision(String projectName, String url, ScmType type, String branchName, String privateKey, + String passPhrase, String token, CodeSvnRegion region, String userName); + + void addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, + String token, CodeSvnRegion region, String userName, String event); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmService.java new file mode 100644 index 0000000..9cfa086 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/IScmService.java @@ -0,0 +1,15 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; + +public interface IScmService { + + RevisionInfo getLatestRevision(String projectName, String url, ScmType type, String branchName, String privateKey, + String paaPhrase, String token, CodeSvnRegion region, String userName); + + void addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, + String token, CodeSvnRegion region, String userName, String event, String hookUrl); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmOauthServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmOauthServiceImpl.java new file mode 100644 index 0000000..3ec698c --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmOauthServiceImpl.java @@ -0,0 +1,59 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.config.SVNConfig; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.dal.pojo.ScmOauthFactory; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class ScmOauthServiceImpl implements IScmOauthService { + + @Resource + private GitConfig gitConfig; + + @Resource + private SVNConfig svnConfig; + + @Override + public RevisionInfo getLatestRevision(String projectName, String url, ScmType type, String branchName, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName) { + log.info("[{}|{}|{}|{}|{}] Start to get the latest oauth revision", projectName, url, type, branchName, userName); + long startEpoch = System.currentTimeMillis(); + try { + return ScmOauthFactory.getScm(projectName, url, type, branchName, privateKey, passPhrase, token, region, userName, null).getLatestRevision(); + } finally { + log.info("It took {}ms to get the latest revision", System.currentTimeMillis() - startEpoch); + } + } + + @Override + public void addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, String token, CodeSvnRegion region, String userName, String event) { + log.info("[{}|{}|{}|{}] Start to add web hook", projectName, url, type, userName); + long startEpoch = System.currentTimeMillis(); + try { + String hookUrl; + if (type == ScmType.CODE_GIT) { + hookUrl = gitConfig.gitHookUrl; + } else if (type == ScmType.CODE_GITLAB) { + hookUrl = gitConfig.gitlabHookUrl; + } else if (type == ScmType.CODE_SVN) { + hookUrl = svnConfig.svnHookUrl; + } else if (type == ScmType.CODE_TGIT) { + hookUrl = gitConfig.tGitHookUrl; + } else { + throw new IllegalArgumentException("Unknown repository type (" + type + ") when add webhook"); + } + ScmOauthFactory.getScm(projectName, url, type, null, privateKey, passPhrase, token, region, userName, event) + .addWebhook(hookUrl); + } finally { + log.info("It took {}ms to add web hook", System.currentTimeMillis() - startEpoch); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmServiceImpl.java new file mode 100644 index 0000000..827569e --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/scm/ScmServiceImpl.java @@ -0,0 +1,73 @@ +package cd.casic.pipeline.scm.service.scm; + + +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.config.P4Config; +import cd.casic.pipeline.scm.config.SVNConfig; +import cd.casic.pipeline.scm.dal.pojo.RevisionInfo; +import cd.casic.pipeline.scm.dal.pojo.ScmFactory; +import cd.casic.pipeline.scm.enums.CodeSvnRegion; +import cd.casic.pipeline.scm.enums.ScmType; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class ScmServiceImpl implements IScmService { + + @Resource + private GitConfig gitConfig; + + @Resource + private SVNConfig svnConfig; + + @Resource + private P4Config p4Config; + + @Override + public RevisionInfo getLatestRevision(String projectName, String url, ScmType type, String branchName, String privateKey, String paaPhrase, String token, CodeSvnRegion region, String userName) { + log.info("[{}|{}|{}|{}] Start to get latest revision", projectName, url, type, userName); + long startEpoch = System.currentTimeMillis(); + try { + return ScmFactory.getScm(projectName, url, type, branchName, privateKey, paaPhrase, token, region, userName, null).getLatestRevision(); + } finally { + log.info("It took {}ms to get the latest revision", System.currentTimeMillis() - startEpoch); + } + } + + @Override + public void addWebhook(String projectName, String url, ScmType type, String privateKey, String passPhrase, + String token, CodeSvnRegion region, String userName, String event, String hookUrl) { + log.info("[{}|{}|{}|{}|{}|{}|{}] Start to add web hook", projectName, url, type, region, userName, event, hookUrl); + if (type == ScmType.CODE_SVN) { + log.info("svn webhook api does not support, ignore"); + return; + } + long startEpoch = System.currentTimeMillis(); + try { + String realHookUrl; + if (StringUtils.isNoneBlank(hookUrl)) { + realHookUrl = hookUrl; + } else { + if (type == ScmType.CODE_GIT) { + realHookUrl = gitConfig.gitHookUrl; + } else if (type == ScmType.CODE_GITLAB) { + realHookUrl = gitConfig.gitlabHookUrl; + } else if (type == ScmType.CODE_TGIT) { + realHookUrl = gitConfig.tGitHookUrl; + } else if (type == ScmType.CODE_P4) { + realHookUrl = p4Config.p4HookUrl; + } else { + throw new IllegalArgumentException("Unknown repository type (" + type + ") when add webhook"); + } + } + ScmFactory.getScm(projectName, url, type, null, privateKey, passPhrase, token, region, userName, event) + .addWebhook(realHookUrl); + } finally { + log.info("It took {}ms to add web hook", System.currentTimeMillis() - startEpoch); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/ITGitService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/ITGitService.java new file mode 100644 index 0000000..11d6ea5 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/ITGitService.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline.scm.service.tgit; + + +import cd.casic.pipeline.scm.dal.pojo.git.GitUserInfo; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import cd.casic.pipeline.scm.enums.TokenTypeEnum; + +public interface ITGitService { + + GitToken refreshToken(String userId, GitToken accessToken); + + GitUserInfo getUserInfoByToken(String token, TokenTypeEnum tokenType); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthService.java new file mode 100644 index 0000000..6328bce --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthService.java @@ -0,0 +1,9 @@ +package cd.casic.pipeline.scm.service.tgit; + + +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; + +public interface TGitOauthService { + + GitToken getAccessToken(String userId); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthServiceImpl.java new file mode 100644 index 0000000..83e6fd6 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitOauthServiceImpl.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.scm.service.tgit; + +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + + +@Service +public class TGitOauthServiceImpl implements TGitOauthService { + + @Resource + private TGitTokenService tGitTokenService; + + @Override + public GitToken getAccessToken(String userId) { + return tGitTokenService.getAccessToken(userId); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitServiceImpl.java new file mode 100644 index 0000000..dc38781 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitServiceImpl.java @@ -0,0 +1,87 @@ +package cd.casic.pipeline.scm.service.tgit; + + +import cd.casic.framework.commons.util.http.OkhttpUtils; +import cd.casic.pipeline.scm.config.GitConfig; +import cd.casic.pipeline.scm.dal.pojo.git.GitUserInfo; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import cd.casic.pipeline.scm.enums.TokenTypeEnum; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.stereotype.Service; + +import java.io.IOException; + +@Service +@Slf4j +public class TGitServiceImpl implements ITGitService { + + @Resource + private GitConfig gitConfig; + + @Resource + private ObjectMapper objectMapper; + + @Override + public GitToken refreshToken(String userId, GitToken accessToken) { + log.info("Start to refresh the token of user {}", userId); + long startEpoch = System.currentTimeMillis(); + try { + String url = gitConfig.tGitUrl + "/oauth/token" + + "?client_id=" + gitConfig.tGitClientId + + "&client_secret=" + gitConfig.tGitClientSecret + + "&grant_type=refresh_token" + + "&refresh_token=" + accessToken.getRefreshToken() + + "&redirect_uri=" + gitConfig.tGitWebhookUrl; + Request request = new Request.Builder() + .url(url) + .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"), "")) + .build(); + Response response = OkhttpUtils.doHttp(request); + okhttp3.ResponseBody body = response.body(); + assert body != null; + String data = body.string(); + return objectMapper.readValue(data, GitToken.class); + } catch (IOException e) { + e.printStackTrace(); + } finally { + log.info("It took {}ms to refresh the token", System.currentTimeMillis() - startEpoch); + } + return null; + } + + @Override + public GitUserInfo getUserInfoByToken(String token, TokenTypeEnum tokenType) { + log.info("Start to get the user info by token[{}]", token); + long startEpoch = System.currentTimeMillis(); + try { + StringBuilder url = new StringBuilder(gitConfig.tGitApiUrl + "/user"); + setToken(tokenType, url, token); + log.info("getToken url>> {}", url); + Request request = new Request.Builder() + .url(url.toString()) + .get() + .build(); + Response response = OkhttpUtils.doHttp(request); + ResponseBody body = response.body(); + assert body != null; + String data = body.string(); + return objectMapper.readValue(data, GitUserInfo.class); + } catch (IOException e) { + e.printStackTrace(); + } finally { + log.info("It took {}ms to get the token", System.currentTimeMillis() - startEpoch); + } + return null; + } + + private void setToken(TokenTypeEnum tokenType, StringBuilder url, String token) { + if (TokenTypeEnum.OAUTH == tokenType) { + url.append("?access_token=").append(token); + } else { + url.append("?private_token=").append(token); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenService.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenService.java new file mode 100644 index 0000000..b4d7f5b --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenService.java @@ -0,0 +1,11 @@ +package cd.casic.pipeline.scm.service.tgit; + + +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; + +public interface TGitTokenService { + + GitToken getAccessToken(String userId); + + Integer saveAccessToken(String userId, String oauthUserId, GitToken tGitToken); +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenServiceImpl.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenServiceImpl.java new file mode 100644 index 0000000..490d638 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/service/tgit/TGitTokenServiceImpl.java @@ -0,0 +1,99 @@ +package cd.casic.pipeline.scm.service.tgit; + +import cd.casic.framework.commons.util.encrypt.AESUtil; +import cd.casic.pipeline.scm.dal.dao.RepositoryTGitTokenMapper; +import cd.casic.pipeline.scm.dal.dto.RepositoryTGitToken; +import cd.casic.pipeline.scm.dal.pojo.oauth.GitToken; +import cd.casic.pipeline.scm.enums.TokenTypeEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.redisson.RedissonRedLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import java.time.ZoneId; + + +@Service +@Slf4j +public class TGitTokenServiceImpl implements TGitTokenService { + + private final String aesKey = ""; + + @Resource + private RedissonClient redissonClient; + + @Resource + private ITGitService tGitService; + + @Resource + private RepositoryTGitTokenMapper repositoryTGitTokenMapper; + + @Override + public GitToken getAccessToken(String userId) { + GitToken accessToken = doGetAccessToken(userId); + if (accessToken == null) { + return null; + } + if (isTokenExpire(accessToken)) { + log.info("try to refresh the git token of user({})", userId); + RLock rLock = redissonClient.getLock("OAUTH_REFRESH_TOKEN_" + userId); + RedissonRedLock lock = new RedissonRedLock(rLock); + + try { + lock.lock(); + GitToken newAccessToken = doGetAccessToken(userId); + assert newAccessToken != null; + if (newAccessToken.getExpiresIn() * 1000 <= System.currentTimeMillis() - 1800 * 1000) { + return refreshToken(userId, newAccessToken); + } else { + return newAccessToken; + } + } finally { + lock.unlock(); + } + } else { + return accessToken; + } + } + + @Override + public Integer saveAccessToken(String userId, String oauthUserId, GitToken tGitToken) { + tGitToken.setAccessToken(AESUtil.encrypt(aesKey, tGitToken.getAccessToken())); + tGitToken.setRefreshToken(AESUtil.encrypt(aesKey, tGitToken.getRefreshToken())); + RepositoryTGitToken repositoryTGitToken = new RepositoryTGitToken(); + repositoryTGitToken.setUserId(userId); + repositoryTGitToken.setOauthUserId(oauthUserId); + repositoryTGitToken.setAccessToken(tGitToken.getAccessToken()); + repositoryTGitToken.setRefreshToken(tGitToken.getRefreshToken()); + repositoryTGitToken.setTokenType(tGitToken.getTokenType()); + repositoryTGitToken.setExpiresIn(tGitToken.getExpiresIn()); + return repositoryTGitTokenMapper.insert(repositoryTGitToken); + } + + private GitToken doGetAccessToken(String userId) { + RepositoryTGitToken token = repositoryTGitTokenMapper.selectOne(RepositoryTGitToken::getUserId, userId); + if (token == null) { + return null; + } + return new GitToken(AESUtil.decrypt(aesKey, token.getAccessToken()), + AESUtil.decrypt(aesKey, token.getRefreshToken()), + token.getTokenType(), token.getExpiresIn(), token.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + } + + private GitToken refreshToken(String userId, GitToken gitToken) { + GitToken token = tGitService.refreshToken(userId, gitToken); + String username = tGitService.getUserInfoByToken(token.getAccessToken(), TokenTypeEnum.OAUTH).getUsername(); + String oauthUserId = username != null ? username : userId; + saveAccessToken(userId, oauthUserId, token); + token.setAccessToken(AESUtil.decrypt(aesKey, token.getAccessToken())); + token.setRefreshToken(AESUtil.decrypt(aesKey, token.getRefreshToken())); + return token; + } + + private Boolean isTokenExpire(GitToken accessToken) { + // 提前半个小时刷新token + return (accessToken.getCreateTime() != null ? accessToken.getCreateTime() : 0) + accessToken.getExpiresIn() * 1000 - 1800 * 1000 <= System.currentTimeMillis(); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/GitUtils.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/GitUtils.java new file mode 100644 index 0000000..fad94e2 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/GitUtils.java @@ -0,0 +1,18 @@ +package cd.casic.pipeline.scm.utils; + +import java.util.regex.Pattern; + +/** + * @author by mianbin + * @Classname GitUtils + * @Date 2025/3/20 20:11 + */ +public class GitUtils { + public static Boolean isLegalHttpUrl(String url) { + return Pattern.matches("http[s]?://([-.a-z0-9A-Z]+)(:[0-9]+)?/(.*).git", url); + } + + public static Boolean isLegalSshUrl(String url) { + return Pattern.matches("git@([-.a-z0-9A-Z]+):(.*).git", url); + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/HashUtil.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/HashUtil.java new file mode 100644 index 0000000..4d61dfb --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/HashUtil.java @@ -0,0 +1,48 @@ +package cd.casic.pipeline.scm.utils; + +import org.hashids.Hashids; + +public class HashUtil { + + private static final String HASH_SALT = "jhy^3(@So0"; + private static final Hashids HASHIDS = new Hashids(HASH_SALT, 8, "abcdefghijklmnopqrstuvwxyz"); + + private static final String OTHER_HASH_SALT = "xlm&gst@Fami1y"; + private static final Hashids OTHER_HASH_IDS = new Hashids(OTHER_HASH_SALT, 4); + + public static String encodeLongId(long id) { + return HASHIDS.encode(id); + } + + public static String encodeIntId(int id) { + return HASHIDS.encode((long) id); + } + + public static long decodeIdToLong(String hash) { + long[] ids = HASHIDS.decode(hash); + return (ids == null || ids.length == 0) ? 0L : ids[0]; + } + + public static int decodeIdToInt(String hash) { + long[] ids = HASHIDS.decode(hash); + return (ids == null || ids.length == 0) ? 0 : (int) ids[0]; + } + + public static String encodeOtherLongId(long id) { + return OTHER_HASH_IDS.encode(id); + } + + public static String encodeOtherIntId(int id) { + return OTHER_HASH_IDS.encode((long) id); + } + + public static long decodeOtherIdToLong(String hash) { + long[] ids = OTHER_HASH_IDS.decode(hash); + return (ids == null || ids.length == 0) ? 0L : ids[0]; + } + + public static int decodeOtherIdToInt(String hash) { + long[] ids = OTHER_HASH_IDS.decode(hash); + return (ids == null || ids.length == 0) ? 0 : (int) ids[0]; + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/RepositoryConfigUtils.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/RepositoryConfigUtils.java new file mode 100644 index 0000000..b2ba8d8 --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/RepositoryConfigUtils.java @@ -0,0 +1,16 @@ +package cd.casic.pipeline.scm.utils; + + +import cd.casic.pipeline.scm.enums.RepositoryConfig; +import cd.casic.pipeline.scm.enums.RepositoryType; + +public class RepositoryConfigUtils { + + public static RepositoryConfig buildConfig(String repositoryId, RepositoryType repositoryType) { + if (repositoryType == null || repositoryType == RepositoryType.ID) { + return new RepositoryConfig(repositoryId, null, RepositoryType.ID); + } else { + return new RepositoryConfig(null, repositoryId, RepositoryType.NAME); + } + } +} diff --git a/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/WebhookUtils.java b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/WebhookUtils.java new file mode 100644 index 0000000..39ebbda --- /dev/null +++ b/modules/pipeline-ci-scm-repository/src/main/java/cd/casic/pipeline/scm/utils/WebhookUtils.java @@ -0,0 +1,20 @@ +package cd.casic.pipeline.scm.utils; + +/** + * @author by mianbin + * @Classname WebhookUtils + * @Date 2025/3/21 10:09 + */ +public class WebhookUtils { + public static final Integer CUSTOM_P4_TRIGGER_VERSION = 2; + + public static Boolean isCustomP4TriggerVersion(String version) { + return getMajorVersion(version) >= CUSTOM_P4_TRIGGER_VERSION; + } + + private static Integer getMajorVersion(String version) { + assert version != null; + String[] strings = version.split("\\."); + return Integer.valueOf(strings[0]); + } +} diff --git a/modules/pipeline-ci-ticket/pom.xml b/modules/pipeline-ci-ticket/pom.xml new file mode 100644 index 0000000..0eb21e6 --- /dev/null +++ b/modules/pipeline-ci-ticket/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + cd.casic.boot + modules + ${revision} + + + cd.casic.pipeline + pipeline-ci-ticket + + + + cd.casic.pipeline + pipeline-ci-commons + + + + cd.casic.pipeline + pipeline-ci-market + 2.0.0-jdk17 + + + + cd.casic.boot + spring-boot-starter-mybatis + + + + \ No newline at end of file diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/ServiceCredentialResource.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/ServiceCredentialResource.java new file mode 100644 index 0000000..2906665 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/ServiceCredentialResource.java @@ -0,0 +1,32 @@ +package cd.casic.pipeline.api; + + +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.dal.pojo.CredentialInfo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + + +@RestController +@Tag(name = "服务-凭据资源") +@RequestMapping("/service/credentials") +public interface ServiceCredentialResource { + + @Operation(summary = "其他服务获取凭据") + @GetMapping("/{projectId}/{credentialId}") + @Parameters({ + @Parameter(name = "projectId", description = "项目ID", required = true), + @Parameter(name = "credentialId", description = "凭据ID", required = true), + @Parameter(name = "publicKey", description = "Base64编码的加密公钥", required = true) + }) + CommonResult get( + @PathVariable + String projectId, + @PathVariable + String credentialId, + @RequestParam + String publicKey); +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/impl/ServiceCredentialResourceImpl.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/impl/ServiceCredentialResourceImpl.java new file mode 100644 index 0000000..e606e47 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/api/impl/ServiceCredentialResourceImpl.java @@ -0,0 +1,30 @@ +package cd.casic.pipeline.api.impl; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.pojo.CommonResult; +import cd.casic.pipeline.api.ServiceCredentialResource; +import cd.casic.pipeline.dal.pojo.CredentialInfo; +import cd.casic.pipeline.service.CredentialService; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class ServiceCredentialResourceImpl implements ServiceCredentialResource { + + @Resource + private CredentialService credentialService; + + @Override + public CommonResult get(String projectId, String credentialId, String publicKey) { + if (StringUtils.isBlank(projectId)) { + throw new ServiceException(-1000, "Invalid projectId"); + } + if (StringUtils.isBlank(credentialId)) { + throw new ServiceException(-1000, "Invalid credentialId"); + } + return CommonResult.success(credentialService.serviceGet(projectId, credentialId, publicKey)); + } +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/constant/TicketMessageCode.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/constant/TicketMessageCode.java new file mode 100644 index 0000000..f84dcdb --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/constant/TicketMessageCode.java @@ -0,0 +1,23 @@ +package cd.casic.pipeline.constant; + +import lombok.NoArgsConstructor; + +/** + * @author by mianbin + * @Classname TicketMessageCode + * @Date 2025/3/22 10:24 + */ +@NoArgsConstructor +public class TicketMessageCode { + + public static final String CERT_ID_TOO_LONG = "2118001"; + public static final String CREDENTIAL_NAME_ILLEGAL = "2118101"; + public static final String CREDENTIAL_ID_ILLEGAL = "2118102"; + public static final String CREDENTIAL_NOT_FOUND = "2118103"; + public static final String CREDENTIAL_FORMAT_INVALID = "2118104"; + public static final String CREDENTIAL_NAME_TOO_LONG = "2118105"; + public static final String CREDENTIAL_ID_TOO_LONG = "2118106"; + public static final String CREDENTIAL_EXIST = "2118107"; + public static final TicketMessageCode INSTANCE = new TicketMessageCode(); + +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dao/CredentialRecordMapper.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dao/CredentialRecordMapper.java new file mode 100644 index 0000000..be560f8 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dao/CredentialRecordMapper.java @@ -0,0 +1,13 @@ +package cd.casic.pipeline.dal.dao; + +import cd.casic.framework.mybatis.core.mapper.BaseMapperX; +import cd.casic.pipeline.dal.dataobject.CredentialRecord; + +/** + * @author by mianbin + * @Classname CredentialRecordMapper + * @Description 。。。 + * @Date 2025/3/20 19:19 + */ +public interface CredentialRecordMapper extends BaseMapperX { +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dataobject/CredentialRecord.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dataobject/CredentialRecord.java new file mode 100644 index 0000000..abeb7dc --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/dataobject/CredentialRecord.java @@ -0,0 +1,47 @@ +package cd.casic.pipeline.dal.dataobject; + +import cd.casic.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * @author by mianbin + * @Classname LogIndicesV2 + * @Description TODO + * @Date 2025/3/19 17:16 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "credential_record", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class CredentialRecord extends BaseDO { + private Long id; + + private String projectId; + + private String credentialId; + + private String credentialName; + + private String credentialUserId; + + private String credentialType; + + private String credentialRemark; + + private String credentialV1; + + private String credentialV2; + + private String credentialV3; + + private String credentialV4; + + private Boolean allowAcrossProject; +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/enums/CredentialType.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/enums/CredentialType.java new file mode 100644 index 0000000..94410f0 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/enums/CredentialType.java @@ -0,0 +1,68 @@ +package cd.casic.pipeline.dal.enums; + +import java.util.HashMap; +import java.util.Map; + +public enum CredentialType { + PASSWORD, // v1 = password, v2=v3=v4=null + ACCESSTOKEN, // v1 = access_token + OAUTHTOKEN, // v1 = oauth_token + USERNAME_PASSWORD, // v1 = username, v2 = password, other = null + SECRETKEY, // v1 = secretKey, other = null + APPID_SECRETKEY, // v1 = appId, v2 = secretKey, other = null + SSH_PRIVATEKEY, // v1 = privateKey, v2=passphrase? + TOKEN_SSH_PRIVATEKEY, // v1 = token, v2 = privateKey, v3=passphrase? + TOKEN_USERNAME_PASSWORD, // v1 = token, v2 = username, v3=password + COS_APPID_SECRETID_SECRETKEY_REGION, // v1 = cosappId, v2 = secretId, v3 = secretKey, v4 = region + MULTI_LINE_PASSWORD; // 密码中有换行符 v1 = password, v2=v3=v4=null + + public static Map getKeyMap(String credentialType) { + Map keyMap = new HashMap<>(); + switch (credentialType) { + case "PASSWORD": + keyMap.put("v1", "password"); + break; + case "ACCESSTOKEN": + keyMap.put("v1", "access_token"); + break; + case "OAUTHTOKEN": + keyMap.put("v1", "oauth_token"); + break; + case "USERNAME_PASSWORD": + keyMap.put("v1", "username"); + keyMap.put("v2", "password"); + break; + case "SECRETKEY": + keyMap.put("v1", "secretKey"); + break; + case "APPID_SECRETKEY": + keyMap.put("v1", "appId"); + keyMap.put("v2", "secretKey"); + break; + case "SSH_PRIVATEKEY": + keyMap.put("v1", "privateKey"); + keyMap.put("v2", "passphrase"); + break; + case "TOKEN_SSH_PRIVATEKEY": + keyMap.put("v1", "token"); + keyMap.put("v2", "privateKey"); + keyMap.put("v3", "passphrase"); + break; + case "TOKEN_USERNAME_PASSWORD": + keyMap.put("v1", "token"); + keyMap.put("v2", "username"); + keyMap.put("v3", "password"); + break; + case "COS_APPID_SECRETID_SECRETKEY_REGION": + keyMap.put("v1", "cosappId"); + keyMap.put("v2", "secretId"); + keyMap.put("v3", "secretKey"); + keyMap.put("v4", "region"); + break; + case "MULTI_LINE_PASSWORD": + keyMap.put("v1", "password"); + break; + } + return keyMap; + } +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Cert.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Cert.java new file mode 100644 index 0000000..fa8c46e --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Cert.java @@ -0,0 +1,35 @@ +package cd.casic.pipeline.dal.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * @author by mianbin + * @Classname Cert + * @Description + * @Date 2025/3/22 10:40 + */ +@Data +@Schema(description = "证书-证书详细内容") +public class Cert { + @Schema(description = "证书ID", required = true) + @NotNull + private final String certId; + @Schema(description = "证书类型", required = true) + @NotNull + private final String certType; + @Schema(description = "创建者", required = true) + @NotNull + private final String creator; + @Schema(description = "证书描述", required = true) + @NotNull + private final String certRemark; + @Schema(description = "创建时间", required = true) + private final long createTime; + @Schema(description = "过期时间", required = true) + private final long expireTime; + @Schema(description = "凭据ID", required = true) + @NotNull + private final String credentialId; +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Credential.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Credential.java new file mode 100644 index 0000000..b173fd7 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/Credential.java @@ -0,0 +1,38 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.dal.enums.CredentialType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Schema(description = "凭据-凭据内容") +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Credential { + @Schema(description = "凭据ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String credentialId; + @Schema(description = "凭据名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String credentialName; + @Schema(description = "凭据类型", requiredMode = Schema.RequiredMode.REQUIRED) + private CredentialType credentialType; + @Schema(description = "凭据描述", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String credentialRemark; + @Schema(description = "最后更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private Long updateTime; + @Schema(description = "凭据内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String v1; + @Schema(description = "凭据内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String v2; + @Schema(description = "凭据内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String v3; + @Schema(description = "凭据内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String v4; + @Schema(description = "最后更新者", requiredMode = Schema.RequiredMode.REQUIRED) + private String updateUser; + @Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED) + private String createUser; +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/CredentialInfo.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/CredentialInfo.java new file mode 100644 index 0000000..fb61c24 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/dal/pojo/CredentialInfo.java @@ -0,0 +1,35 @@ +package cd.casic.pipeline.dal.pojo; + +import cd.casic.pipeline.dal.enums.CredentialType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Schema(description = "凭据-凭据内容") +@AllArgsConstructor +@NoArgsConstructor +public class CredentialInfo { + + @Schema(description = "Base64编码的加密公钥", requiredMode = Schema.RequiredMode.REQUIRED) + private String publicKey; + + @Schema(description = "凭据类型", requiredMode = Schema.RequiredMode.REQUIRED) + private CredentialType credentialType; + + @Schema(description = "加密后经过Base64编码的凭据", requiredMode = Schema.RequiredMode.REQUIRED) + private String v1; + + @Schema(description = "加密后经过Base64编码的凭据", requiredMode = Schema.RequiredMode.REQUIRED) + private String v2; + + @Schema(description = "加密后经过Base64编码的凭据", requiredMode = Schema.RequiredMode.REQUIRED) + private String v3; + + @Schema(description = "加密后经过Base64编码的凭据", requiredMode = Schema.RequiredMode.REQUIRED) + private String v4; + + @Schema(description = "当前凭据是否允许跨项目使用", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private Boolean allowAcrossProject; +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialHelper.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialHelper.java new file mode 100644 index 0000000..41739ba --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialHelper.java @@ -0,0 +1,37 @@ +package cd.casic.pipeline.service; + + +import cd.casic.framework.commons.util.encrypt.AESUtil; +import cd.casic.framework.commons.util.encrypt.DHUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + + +@Component +public class CredentialHelper { + + private final String aesKey = "MB/R%3{?OS}IeGT21"; + + public String decryptCredential(String aesCredential) { + if (StringUtils.isEmpty(aesCredential) || StringUtils.isBlank(aesCredential)) { + return null; + } + return AESUtil.decrypt(aesKey, aesCredential); + } + + public String encryptCredential(String aesEncryptCredential, byte[] publicKeyByteArray, byte[] serverPrivateKeyByteArray) { + if (StringUtils.isEmpty(aesEncryptCredential) || StringUtils.isBlank(aesEncryptCredential)) { + return null; + } + try { + String credential = AESUtil.decrypt(aesKey, aesEncryptCredential); + byte[] credentialEncryptedContent = DHUtil.encrypt(credential.getBytes(StandardCharsets.UTF_8), publicKeyByteArray, serverPrivateKeyByteArray); + return new String(Base64.getEncoder().encode(credentialEncryptedContent)); + } catch (Throwable ignored) { + throw ignored; + } + } +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialService.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialService.java new file mode 100644 index 0000000..100c121 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialService.java @@ -0,0 +1,12 @@ +package cd.casic.pipeline.service; + + +import cd.casic.pipeline.dal.pojo.Credential; +import cd.casic.pipeline.dal.pojo.CredentialInfo; + +public interface CredentialService { + + Credential serviceGet(String projectId, String credentialId); + + CredentialInfo serviceGet(String projectId, String credentialId, String publicKey); +} diff --git a/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialServiceImpl.java b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialServiceImpl.java new file mode 100644 index 0000000..e808424 --- /dev/null +++ b/modules/pipeline-ci-ticket/src/main/java/cd/casic/pipeline/service/CredentialServiceImpl.java @@ -0,0 +1,74 @@ +package cd.casic.pipeline.service; + + +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.util.encrypt.DHKeyPair; +import cd.casic.framework.commons.util.encrypt.DHUtil; +import cd.casic.pipeline.dal.dao.CredentialRecordMapper; +import cd.casic.pipeline.dal.dataobject.CredentialRecord; +import cd.casic.pipeline.dal.pojo.Credential; +import cd.casic.pipeline.dal.pojo.CredentialInfo; +import cd.casic.pipeline.dal.enums.CredentialType; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.Base64; + + +@Service +public class CredentialServiceImpl implements CredentialService { + + @Resource + private CredentialHelper credentialHelper; + @Resource + private CredentialRecordMapper credentialRecordMapper; + + @Override + public Credential serviceGet(String projectId, String credentialId) { + CredentialRecord record = credentialRecordMapper.selectOne(CredentialRecord::getProjectId, projectId, CredentialRecord::getCredentialId, credentialId); + if (record == null) { + throw new ServiceException(-1000, "credentialId:" + credentialId + "does not exist"); + } + return Credential.builder() + .credentialId(record.getCredentialId()) + .credentialName(record.getCredentialName()) + .credentialType(CredentialType.valueOf(record.getCredentialType())) + .credentialRemark(record.getCredentialRemark()) + .v1(credentialHelper.decryptCredential(record.getCredentialV1())) + .v2(credentialHelper.decryptCredential(record.getCredentialV2())) + .v3(credentialHelper.decryptCredential(record.getCredentialV3())) + .v4(credentialHelper.decryptCredential(record.getCredentialV4())) + .updateUser("这里从租户获取到用户id,占位") + .build(); + } + + @Override + public CredentialInfo serviceGet(String projectId, String credentialId, String publicKey) { + CredentialRecord record = credentialRecordMapper.selectOne(CredentialRecord::getProjectId, projectId, CredentialRecord::getCredentialId, credentialId); + if (record == null) { + throw new ServiceException(-1000, "credentialId:" + credentialId + "does not exist"); + } + return credentialInfo(publicKey, record); + } + + private CredentialInfo credentialInfo(String publicKey, CredentialRecord credentialRecord) { + byte[] publicKeyByteArray = Base64.getDecoder().decode(publicKey); + DHKeyPair severDHKeyPair = DHUtil.initKey(publicKeyByteArray); + assert severDHKeyPair != null; + byte[] serverPublicKeyByteArray = severDHKeyPair.getPublicKey(); + byte[] serverPrivateKeyByteArray = severDHKeyPair.getPrivateKey(); + String serverBase64PublicKey = new String(Base64.getEncoder().encode(serverPublicKeyByteArray)); + + String credentialV1 = credentialHelper.encryptCredential(credentialRecord.getCredentialV1(), publicKeyByteArray, serverPrivateKeyByteArray); + assert credentialV1 != null; + String credentialV2 = credentialHelper.encryptCredential(credentialRecord.getCredentialV2(), publicKeyByteArray, serverPrivateKeyByteArray); + String credentialV3 = credentialHelper.encryptCredential(credentialRecord.getCredentialV3(), publicKeyByteArray, serverPrivateKeyByteArray); + String credentialV4 = credentialHelper.encryptCredential(credentialRecord.getCredentialV4(), publicKeyByteArray, serverPrivateKeyByteArray); + + return new CredentialInfo(serverBase64PublicKey, + CredentialType.valueOf(credentialRecord.getCredentialType()), + credentialV1, credentialV2, credentialV3, credentialV4, + credentialRecord.getAllowAcrossProject()); + } + +} diff --git a/ops-server/src/main/resources/application-dev.yaml b/ops-server/src/main/resources/application-dev.yaml index e240ff4..9f5995d 100644 --- a/ops-server/src/main/resources/application-dev.yaml +++ b/ops-server/src/main/resources/application-dev.yaml @@ -40,12 +40,12 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://1.14.125.6:13306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root password: 1qaz!QAZ slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://1.14.125.6:13306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root password: 1qaz!QAZ diff --git a/ops-server/src/main/resources/application-local.yaml b/ops-server/src/main/resources/application-local.yaml index 56be1ad..2237153 100644 --- a/ops-server/src/main/resources/application-local.yaml +++ b/ops-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://1.14.125.6:13306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -63,7 +63,7 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://1.14.125.6:13306/ops-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true username: root password: 1qaz!QAZ diff --git a/pom.xml b/pom.xml index 9c1b4f3..ef54a00 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,15 @@ system-framework app-plugins ops-server + modules/pipeline-ci-commons + modules/pipeline-ci-log + modules/pipeline-ci-event + modules/pipeline-ci-ticket + modules/pipeline-ci-quality + modules/pipeline-ci-scm-repository + modules/pipeline-ci-project + modules/pipeline-ci-process + modules/pipeline-ci-market