CCS项目持续集成

news/2024/9/23 7:25:14/

​ 因工作需要,用户提出希望可以做ccs项目的持续集成,及代码提交后能够自动编译并提交到svn。调研过jenkins之后发现重新手写更有性价比,所以肝了几晚终于搞出来了,现在分享出来。

​ 先交代背景:

	1.	代码分两部分,一部分在git上,一部分在svn上2.	希望git上提交的代码时和svn上提交代码时都触发持续集成。

​ 实现功能:

  1. git上提交代码时自动触发持续集成

  2. svn上提交代码时,并在备注中以“编译”开头时触发持续集成

  3. 持续集成功能:

    a. 将git上的代码复制到 svn的 编译目录(记为 X)中

    b. 将svn的源码目录(记为S)复制到svn的编译目录X的子目录(X1)中

    c. 执行ccs的编译命令,编译ccs项目,

    d. 将编译出的结果文件分别复制到 svn的多个目录中,

    e. 将编译结果文件提交到svn,备注日志中包括git上的版本信息、svn源码目录(S)的版本信息。

实现说明:

  1. 使用springboot 搭建一个web项目,并提供一个接口用户触发持续集成,记为接口X

  2. 在git配置webhook,在代码检入时调用接口X (下面的配置需要使用管理员的账号)

    在这里插入图片描述

  3. 在svn中编写钩子函数,在备注信息以”编译“开头时,调用接口x

    # 构造函数代码片段,此代码在svn的仓库目录下的hooks目中,文件名称为 post-commit  对的,没有后缀
    COMMENT=$(svnlook log -r $REV $REPOS)if echo "$COMMENT" | grep -qE '^编译'; thenecho "提交日志以'编译'开头。"  >> ${SVN_LOG_FILE_PATH}curl -X post -v http://xxxx/cicd/xxx #这个就是接口x的地址了
    
  4. 接口X的具体逻辑如下:

    整体逻辑是:

    a. 将git 和svn上的代码更新到本地

    b. 将文件复制到指定目录中

    c. 执行编译命令: 编译命令使用的是ccs的编译命令

    d. 判断编译是否成功,成功的话则将编译结果复制到指定目录中

    e. 获取源码目录的最新版本号及备注信息,并拼接成备注信息,将结果文件提交到svn上。

    先将其关键代码展示:

    // 操作git,使用的是org.eclipse.jgit  5.13.3.202401111512-r
    /*** 克隆仓库** @throws Exception*/public void cloneRep(boolean force) throws Exception {File targetDirectory = new File(getLocalPath());boolean exists = targetDirectory.exists();if (exists && force) {FileUtil.del(targetDirectory);} else if (exists) {return;}Git.cloneRepository().setURI(getRepUrl()).setBranch(getBranch()).setDirectory(targetDirectory).setCredentialsProvider(new UsernamePasswordCredentialsProvider(getUsername(), getPassword())).call();}/** 获取仓库版本 */public String getRepVersion(){File localFile = new File(getLocalPath());boolean exists = localFile.exists();if (!exists) {return "";}try (Git git = Git.open(localFile)) {final Iterable<RevCommit> revCommits = git.log().setMaxCount(1).call();final RevCommit revCommit = revCommits.iterator().next();final String commitDate = DateUtil.format(revCommit.getAuthorIdent().getWhen(), "yyyy-MM-dd HH:mm:ss");final String commitName = revCommit.getAuthorIdent().getName();return String.format("%s(%s)", commitName,commitDate);} catch (Exception e) {log.error(e.getMessage(), e);}return "";}/** 更新仓库 */public void updateRep(boolean force) throws Exception {File localFile = new File(getLocalPath());boolean exists = localFile.exists();if (!exists) {cloneRep(force);return;}try (Git git = Git.open(localFile)) {if (force) {// 撤销所有未提交的本地修改git.reset().setMode(ResetCommand.ResetType.HARD).call();// 删除未跟踪的文件和目录git.clean().setCleanDirectories(true) // 递归清理子目录.call();}// 设置凭据CredentialsProvider cp = new UsernamePasswordCredentialsProvider(getUsername(), getPassword());git.fetch().setCredentialsProvider(cp).call();git.pull().setRebase(true) // 默认情况下合并(merge),这里改为变基(rebase).setCredentialsProvider(cp).call();} catch (RepositoryNotFoundException e) {// 未找到仓库cloneRep(true);}}
    
// 操作 svn
static {DAVRepositoryFactory.setup();SVNRepositoryFactoryImpl.setup();FSRepositoryFactory.setup();}public void updateRep() throws Exception {updateRep(true);}public void updateRep(boolean force) throws Exception {log.info("updateRep");BasicAuthenticationManager authManager = new BasicAuthenticationManager(getUsername(), getPassword());SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(getRepUrl()));repository.setAuthenticationManager(authManager);File targetFile = new File(getLocalPath(), "\\");if (force && targetFile.exists()) {// 撤销本地修改SVNWCClient wcClient = SVNClientManager.newInstance(null, authManager).getWCClient();wcClient.doRevert(new File[]{targetFile}, SVNDepth.INFINITY, null);}// 检出SVNUpdateClient updateClient = SVNClientManager.newInstance(null, authManager).getUpdateClient();updateClient.doCheckout(repository.getLocation(), targetFile, SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, false);}public void commit(List<File> delFileList) throws Exception {commit("", delFileList);}public void commit(String commitMsg, List<File> delFileList) throws Exception {if (!isNeedCommit()) {log.info("不需要提交,直接跳过!");return;}BasicAuthenticationManager authManager = new BasicAuthenticationManager(getUsername(), getPassword());SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(getRepUrl()));repository.setAuthenticationManager(authManager);SVNCommitClient client = SVNClientManager.newInstance(null, authManager).getCommitClient();File[] pathsToCommit = {new File(getLocalPath())};List<SVNURL> delSvnUrlList = new ArrayList<>();if (delFileList != null && !delFileList.isEmpty()) {for (File file : delFileList) {SVNURL svnUrl = getSvnUrl(file);if (isURLExist(svnUrl)) {delSvnUrlList.add(svnUrl);} else {file.delete();}}}if (!delSvnUrlList.isEmpty()) {SVNURL[] array = delSvnUrlList.toArray(new SVNURL[0]);// 先把老的旧文件删除掉。client.doDelete(array, StrUtil.isBlank(commitMsg) ? getCommitMsg() : commitMsg);}// 添加新增加的文件SVNClientManager.newInstance(null, authManager).getWCClient().doAdd(pathsToCommit, true, true, true, SVNDepth.INFINITY, true, false, true);SVNCommitInfo commitInfo = client.doCommit(pathsToCommit, false,StrUtil.isBlank(commitMsg) ? getCommitMsg() : commitMsg, false, true);log.info("Committed revision: {}", commitInfo.getNewRevision());}private boolean isURLExist(SVNURL url) {try {BasicAuthenticationManager authManager = new BasicAuthenticationManager(getUsername(), getPassword());SVNRepository svnRepository = SVNRepositoryFactory.create(url);svnRepository.setAuthenticationManager(authManager);SVNNodeKind nodeKind = svnRepository.checkPath("", -1);return nodeKind == SVNNodeKind.NONE ? false : true;} catch (SVNException e) {log.error("isURLExist error", e);}return false;}private SVNURL getSvnUrl(File file) throws SVNException {String svnUrl = StrUtil.replace(file.getAbsolutePath(), getRepLocalBasePath(), getRepUrl());svnUrl = svnUrl.replace("\\", "/");log.info("getSvnUrl: {}", svnUrl);return SVNURL.parseURIEncoded(svnUrl);}/**
获取svn指定子目录的最后提交版本。
*/public long getRepVersion() {try {log.info("getRepVersion");BasicAuthenticationManager authManager = new BasicAuthenticationManager(getUsername(), getPassword());SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(getRepUrl()));log.info("getRepVersion repository.getLocation():{}", repository.getLocation().toString());repository.setAuthenticationManager(authManager);long version = repository.getLatestRevision();log.info("getRepVersion version:{}", version);File versionFile = new File(getRepLocalBasePath() + getSvnVersionPath());SVNStatus status = SVNClientManager.newInstance(null, authManager).getStatusClient().doStatus(versionFile, false);if (status != null) {version = status.getCommittedRevision().getNumber();}return version;} catch (Exception e) {log.error("getRepVersion error", e);}return -1;}/**
获取svn指定版本的日志信息.
*/public String getLogInfo(long revision) {try {BasicAuthenticationManager authManager = new BasicAuthenticationManager(getUsername(), getPassword());SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(getRepUrl()));log.info("getRepVersion repository.getLocation():{}", repository.getLocation().toString());repository.setAuthenticationManager(authManager);log.info("getRepVersion version:{}", revision);File versionFile = new File(getRepLocalBasePath() + getSvnVersionPath());StringBuffer logInfoBuf = new StringBuffer();ISVNLogEntryHandler handler = logEntry -> {String logInfo = String.format("%s %s",DateUtil.format(logEntry.getDate(), "yyyyMMddHH:mm:ss"),logEntry.getMessage());logInfoBuf.append(logInfo);log.info("logInfo {}: {}", logEntry.getRevision(), logInfo);};SVNLogClient logClient = new SVNLogClient(authManager, null);logClient.doLog(new File[]{versionFile},SVNRevision.create(revision), SVNRevision.create(revision),true, true,1, handler);return logInfoBuf.toString();} catch (Exception e) {log.error("getLogInfo error", e);}return "";}
# ccs编译命令
@echo off
set ccs_home=E:\programe\ccs124
set workspace=yyyy
set proj_home=xxxxset eclipsec="%ccs_home%\ccs\eclipse\eclipsec"
set proj_name=zzzrem rmdir /S /Q "%proj_home%"\Release
rem TortoiseProc.exe /command:remove /y /path:"%proj_home%\Release\"rmdir /S /Q "%workspace%"mkdir "%workspace%"rem 导入项目"%eclipsec%" -noSplash -data "%workspace%" -application com.ti.ccstudio.apps.projectImport -ccs.location "%proj_home%" -ccs.renameTo "%proj_name%"  >> ./logs/gmakeLog_%date:~0,4%%date:~5,2%%date:~8,2%.logrem 清空项目.
"%eclipsec%" -noSplash -data "%workspace%" -application com.ti.ccstudio.apps.projectBuild -ccs.projects "%proj_name%" -ccs.clean >> ./logs/gmakeLog_%date:~0,4%%date:~5,2%%date:~8,2%.logrem 编译.
"%eclipsec%" -noSplash -data "%workspace%" -application com.ti.ccstudio.apps.projectBuild -ccs.projects "%proj_name%" -ccs.configuration Release >> ./logs/gmakeLog_%date:~0,4%%date:~5,2%%date:~8,2%.log

http://www.ppmy.cn/news/1433165.html

相关文章

日志分析简单总结

1、分析日志的目的 误报&#xff1a;不是攻击而上报成攻击 漏报&#xff1a;是攻击而没有防御的情况 日志分析可以判断是否误判或者漏判&#xff0c;可以溯源攻击行为 在护网作为防守方必备的技能&#xff08;分析NGAF和态势感知&#xff0c;发现异常&#xff09; 2、攻击出现…

Linux内核驱动开发-006内核定时器

1驱动程序 /*************************************************************************> File Name: timer.c> Author: yas> Mail: rage_yashotmail.com> Created Time: 2024年04月23日 星期二 19时20分42秒*************************************************…

MongoDB聚合运算符:$setUnion

MongoDB聚合运算符&#xff1a;$setUnion 文章目录 MongoDB聚合运算符&#xff1a;$setUnion语法使用举例 $setUnion聚合运算符返回两个或多个数组的并集。 语法 { $setUnion: [ <expression1>, <expression2>, ... ] }<expression>为可解析为数组的表达式。…

导出JVM的线程信息

1. 查询出Java应用的进程的PID ps -ef|grep java 此时的PID是 33 2. 使用JDK自带的工具jstack导出日志 jstack -l 33 > 2022jstack.log 3.然后直接下载

Centos7系统下安装Nginx并配置域名转发实现域名访问

感谢李天健同学辛苦创作&#xff0c;对于Nginx配置未完成的同学请移步他的博客。 传送门&#xff1a;Centos7系统下安装Nginx并配置域名转发实现域名访问 传送门2&#xff1a;1.24.0

使用yolo识别模型对比两张图片并标记不同(2)

上篇文章有漏洞&#xff0c;在这里补充下&#xff0c;比如要识别第二张图相对于第一张图的违建是否拆除了 第一步旋转对其后&#xff0c;图片会有黑色的掩码&#xff0c;如果旋转角度大的话&#xff0c;没识别出来的框可能不是已经拆除了&#xff0c;而是因为黑色掩码遮挡&…

【hackmyvm】 Quick2靶机

渗透流程 渗透开始1.IP地址 获取2.端口扫描3.任意文件读取4.扫描目录5.总结信息6.漏洞扫描7.php_filter_chain_generator.py使用8.提权 渗透开始 1.IP地址 获取 ┌─[✗]─[userparrot]─[~] └──╼ $fping -ag 192.168.9.0/24 2>/dev/null 192.168.9.124 本机 192.1…

ORB-SLAM2算法单目流程

ORB-SLAM系列算法框架比较复杂&#xff0c;下面来梳理一下单目算法的流程。 一&#xff1a;单目初始化 单目初始化也就是单目的地图初始化。流程如下&#xff1a; * Step 1&#xff1a;&#xff08;未创建&#xff09;得到用于初始化的第一帧&#xff0c;初始化需要两帧 * …