开源测试工具 [普兰能效平台] 研发协作一站式管理平台 (http://www.seqcer.com) 开源

槽神 · 2019年12月11日 · 最后由 槽神 回复于 2020年01月08日 · 4456 次阅读

说明

  • 社区开源地址
  • SEPP(Software Engineering Productivity Platform),研发能效平台。平台结合了成熟了项目管理体系和过程模型,贯穿敏捷产品研发生命周期的一站式服务。
  • 现如今类似的协作工作非常多,比如 JIRA、福报厂的 teambition、鹅厂的 TAPD、度娘的 iCafe、平安系的神兵,以及古老的禅道等等,各有各的特色!最初我们在用一些只关注项目或者敏捷协作的工具,后来发现一些过程的细节管理需要集成类似 Testlink、Jenkins 等很多工具来弥补。再后来看到那么多的过程数据躺在那里毫无价值,我们就想用一些数据挖掘的技巧来分析研发过程的效率。
  • 由于一些不可说的原因,我们没能第一时间采购到 JIRA 这种牛 X 的工具,我就索性自己用最简单、时兴的技术栈撸了一个,一边用一边跟研发、测试、项目团队的兄弟们撕;一边规划一边改……同时还要一边努力地拒绝一些来自高管的奇怪需求(或许接纳了更多,嘿嘿)。
  • 经过一年的使用和打磨,我们觉得差不多基本框架成型了,还有很多基础工具链的集成虽然没有全部完成,也就是时间的问题了,所以就申请把这个东西开源了。其实并不是做成一个什么样的产品,只是想给一些初学者一点参考的东西和学习的信心,因为我们也是野路子测开出身。
  • 几大缺陷:
    • 整个管理风格看起来很 CMM,如果觉得不能接受,希望给点建设性建议;
    • 开源的功能肯定不完整,毕竟是企业内部应用;
    • 后端代码勉强能看,但是基本跟设计模式无关,妥妥的 CRUD 大合集;前端代码模块化没做,写得比较乱;
    • 没怎么写文档,但是流程上的控制逻辑比较复杂,而且自定义支持得比较少

演示地址

http://www.seqcer.com

  • 推荐注册,并创建自己的项目,便于隔离数据胡搞而不影响其他试用者
  • 仅对 chrome 浏览器做了完全适配,其他 chromium 核心浏览器或者 firefox、safari 也能使用,但是不推荐

仓库地址:

本地化部署问题解决步骤:

  • 先赏个 STAR
  • 再加 QQ 群:362260709
  • 再问问题,当然,建议提问之前仔细看完下面的说明

技术栈

  • 前端:vue2、axios、element 等等等等
  • 后端:springboot、guava、lombok 等等等等
  • 基础组件:mariadb(10.3)、nginx(1.15.3)、nodejs(8.12.0)、fastdfs、npm(6.7.0)、webpack4 等等
  • 插件:swagger2、quartz、aviator、h2 等等

后端

启动方式:
  • Main Class:com.pr.sepp.SeppApplication(线上可注释掉@EnableSwagger2
  • 本地 VM options:-Denv=local
  • 注意:本地开发请务必安装好 IDE 的 lombok 插件
  • 线上部署:
    • rm -rf src/main/resources/spring.properties
    • mvn clean package -Dmaven.test.skip=true
    • mv target/sepp*.jar ${your_path}/sepp.jar
    • java -Dpath=${your_conf_path}/spring.properties -jar ${your_path}/sepp.jar &
  • 集群:已测试 HAProxy、keepalived,其余未测试
组件使用说明
  • mariadb(>= 10.3),必须设置 lower_case_table_names=1,参考 conf/database/my.conf
  • FastDfs,与 nginx 绑定使用,二者配置参考 conf/fastdfs/*.properties、conf/nginx/*.properties
  • octopus 监控需要配置 octopus.admin.address 和 context.env 两个参数
  • Quartz 请注意 spring-boot-starter-quartz 和 boot 版本的兼容性问题,最好自己指定版本(参考 pom.xml)
  • 邮件服务、Jenkins 服务、git 仓库服务、sonarQube 服务、LDAP 认证服务,皆可使用超级管理员进入系统设置进行配置,持久化到数据库,同时 Jenkins 服务和邮件服务也可以通过配置文件实现,其中 Jenkins 使用持久化的配置需要配置 jenkins.enable-programmatic=false
  • 基础设施>>监控中心,请参考:https://github.com/fudax/octopus 工程说明,并且更新 spring.properties 和前端 src/components/monitor/MonitorAdmin.vue 文件配置

前端

安装步骤

git clone https://github.com/purang-fintech/seppf.git
cd seppf
npm install

本地开发,默认服务端口 8080

npm run dev

构建生产

npm run build

License

MIT

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 24 条回复 时间 点赞
槽神 #26 · 2020年01月08日 Author
魔幻云 回复

看代码,加解密的 key 要一致,源码里默认是写死的,没有给你配置的机会😂

private static final String ERROR_EN_MSG = "用户名密码解密失败";
private static final String ERROR_DE_MSG = "用户名密码解密失败";
private static final String CIPHER_INSTANCE = "AES/CBC/PKCS5Padding";
private static final String SERIAL_KEY = "0102030405060708";
private static final String ENCRYPT_STYLE = "AES";
槽神 回复

谢谢大佬,构建可以了,不过还有一个问题配置文件里面的 AES 加密(密钥采用里面默认自定义)提示解密失败
配置如下:

dbc.username=这个地方换成自己加密后的user
jdbc.password=换成加密后的pwd
signing.secret=1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ

槽神 #24 · 2020年01月08日 Author
魔幻云 回复

不好意思,代码内外版本同步有误,已解决,请重新拉代码,应该能解决问题

槽神 回复

环境如下:
1.java:1.8.0_181
2.maven 版本:apache-maven-3.6.0

构建命令:使用官方
1.mvn clean package -Dmaven.test.skip=true
2.官方图

3.git 代码分支:master,日志版本信息如下:

备注:我们这边仅先尝试部署起来进行功能查看,所以要是能直接提供 jar 包,我就不必本地构建啦。

报错信息:

[INFO] /geelyapp/seppb/src/main/java/com/pr/sepp/utils/fasfdfs/conn/FdfsConnectionPool.java: Recompile with -Xlint:unchecked for details.
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /geelyapp/seppb/src/main/java/com/pr/sepp/utils/jenkins/JenkinsClientManager.java:[34,89] cannot find symbol
  symbol:   method getBuildJenkinsClientProviderMap()
  location: variable jenkinsClientProvider of type com.pr.sepp.utils.jenkins.JenkinsClientProvider
[ERROR] /geelyapp/seppb/src/main/java/com/pr/sepp/utils/jenkins/JenkinsClientManager.java:[37,84] cannot find symbol
  symbol:   method getJenkinsClientProviderMap()
  location: variable jenkinsClientProvider of type com.pr.sepp.utils.jenkins.JenkinsClientProvider
[INFO] 2 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  23.076 s
[INFO] Finished at: 2020-01-08T09:12:05+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project sepp: Compilation failure: Compilation failure:
[ERROR] /geelyapp/seppb/src/main/java/com/pr/sepp/utils/jenkins/JenkinsClientManager.java:[34,89] cannot find symbol
[ERROR]   symbol:   method getBuildJenkinsClientProviderMap()
[ERROR]   location: variable jenkinsClientProvider of type com.pr.sepp.utils.jenkins.JenkinsClientProvider
[ERROR] /geelyapp/seppb/src/main/java/com/pr/sepp/utils/jenkins/JenkinsClientManager.java:[37,84] cannot find symbol
[ERROR]   symbol:   method getJenkinsClientProviderMap()
[ERROR]   location: variable jenkinsClientProvider of type com.pr.sepp.utils.jenkins.JenkinsClientProvider
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project sepp: Compilation failure
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
    at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1161)
    at org.apache.maven.plugin.compiler.CompilerMojo.execute (CompilerMojo.java:168)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
[ERROR]
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

魔幻云 回复

1、你是 IDE 报错还是命令行 mvn package 报错?
2、你确定你的代码版本是最新的吗?
3、你确定你按照 readme 一步一步操作了没有?
4、我这 pom.xml 写的清清楚楚,您还需要什么信息,我一个个给您找?

阿三 回复

我也是同样的报错,楼主可否提供一下 jdk 版本和 maven 版本,github 说明太粗略。谢谢

槽神 回复

这个编译失败?

23楼 已删除
22楼 已删除
槽神 #17 · 2019年12月26日 Author
阿三 回复

No space left on device……百度一下啥意思吧,google 就算了,看不懂

槽神 #15 · 2019年12月19日 Author

添加了几张基本的逻辑控制说明思维导图

妞妞 回复

……
那你自己不会写一句么:

mv target/sepp*.jar /opt/seppb/sepp.jar

部署后端的时候 最后一步报错了 java -Dpath=/opt/seppb/conf/spring.properties -jar /opt/seppb/sepp.jar &
提示:Unable to access jarfile /opt/seppb/sepp.jar

槽神 回复

大佬 加群麻烦通过下。

槽神 回复

嗯嗯 我用了 8.X 的还是 dev 可以 build 报错。

槽神 #13 · 2019年12月18日 Author

@ 米阳 MeYoung 看声明

槽神 #11 · 2019年12月16日 Author

未提交代码的组件权限控制设计:

权限系统-1.资源配置

目前权限系统的权限控制粒度能控制到按钮级别,按钮和接口权限同步,同时保证前端实现权限控制的同时,保证后端服务的安全(接口权限)

一:菜单入口

权限配置->资源配置

二:权限配置

1.通过菜单入口进入权限资源配置页面

2.添加对应的资源权限

a.组件名:该值是按钮所属页面组件的名称()

b.组件id:该值是开发自己赋予的值(该值要确保在当前页面是唯一的)

c.接口:该按钮功能下对应的接口权限(按钮可能存在一对多的情况,目前支持单一接口的权限)

d.接口类型:略

e.角色:按钮和接口对应的角色

f.是否生效:略

三:前端组件使用

目前前端提供了两个权限组件用于权限控制(auth.js、has.js)

1.指令 v-auth
使用该指令后,就可以通过页面配置权限的方式动态的给使用该指令的按钮分配权限
对于需要权限控制的按钮

例如资源配置里的删除按钮

<el-button v-auth="{id:'deleteResource',component:'ResourceConfig'}" icon="el-icon-delete" @user1="deleteResourceConfig(scope.row)" type="text"
                                   class="oper-button"
                                   style="color:#EE6F6F"></el-button>
v-auth指令中两个必须参数;id该页面中该按钮的唯一标识;component为当前组件的name;

注意:在确认使用 v-has 的时候必须在该组件测 created 方法中加入 this.$auth();

如图:

所以前端使用 v-auth 指令分两三步:
  • 1.在需要的按钮上加上 v-auth(并添加唯一的标识 id,同时加上当前组件 name)
  • 2.在当前组件的 created 方法调用 this.$auth()
  • 3.请到配置页面配置相应的按钮权限
2.v-has 指令
v-has指令属于前端控制指令、仅对前端的按钮做权限控制,适合资源配置页面,虽然资源配置页面也使用v-auth指令,但是对于资源配置页面的按钮权限来说,使用v-has更加合适
<el-button v-has="['admin']" style="float: right; padding: 3px 0" type="text" @user2="addResource">添加</el-button>

v-has 指令的参数为数组形式,可以加入多个角色,在这里个人不推荐使用 id 作为参数,而是采用 code

前端指令代码

1.auth.js

function install(Vue, options = {}) {
    Vue.directive(options.name || "auth", {
        inserted(el, binding) {
            if (!check(binding.value)) {
                el.parentNode && el.parentNode.removeChild(el);
            }
        }
    });
}

function getCurrentAuthority() {
    return JSON.parse(localStorage.getItem("roleIds"));
}

function check(authInfo) {
    const currentAuthority = getCurrentAuthority();
    alert(this.$options.name);
    let auth = localStorage.getItem(authInfo.component);
    let authJson = JSON.parse(auth);
    for (let authData of authJson) {
        if (authData.authId == authInfo.id) {
            return currentAuthority.some(item => authData.roleIds.includes(item));
        }
    }
    return false;
}

export default {install};

2.has.js

function install(Vue, options = {}) {
    Vue.directive(options.name || "has", {
        inserted(el, binding) {
            if (!check(binding.value)) {
                el.parentNode && el.parentNode.removeChild(el);
            }
        }
    });
}


function getCurrentAuthority() {
    return JSON.parse(localStorage.getItem("roleCodes"));
}

function check(roles) {
    return getCurrentAuthority().some(item => roles.includes(item));;
}

export default {install};

四:后端接口控制

对于在资源配置页面配置过的接口需要在后端接口加上相应的权限标识,以让配置生效

例如在上面配置的删除资源配置的权限接口可以加上@ApiPermission注解以让该接口的权限生效

注解@ApiPermission的使用
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiPermission {

    Role[] roles() default ALL;

    boolean dynamic() default true;

    RoleGroup[] groups() default RoleGroup.ALL;

    enum RoleGroup {
        ALL
    }

}

目前该注解有三个参数:roles、dynamic、groups

groups 可以忽略

roles和dynamic是成对出现的,如果我们不想动态配置接口的权限,可以将dynamic设置为false,然后设置roles,否则单独设置roles并不会生效,因为默认情况dynamic为true会从数据库读取相关角色信息

虽然没看代码,但是技术栈就很不错,赞。

槽神 回复

谢谢大佬

米阳MeYoung 回复

提交的时候不知道怎么漏掉了,已经好了


dev.dev.js 文件缺失
直接 test.js 好像可以用

果断 start 支持。 我也在做,很多东西可以参考学习。

顶!有东西可以来分享啦~

槽神 回复

感谢大佬的分享

@0x88 你要的东西来了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册