SVN

整理收集SVN相关的东东……

服务器端

该章节介绍一下SVN的服务器端

ubuntu 22.04

这里使用的是:subversion

安装和检测

svn
sudo apt update
sudo apt install subversion
#   安装完成,检测一下
svn
svn help
svnadmin help
            

ubuntu 22.04 安装 subversion

ubuntu 22.04 安装 subversion 之后,svn help

ubuntu 22.04 安装 subversion 之后,svnadmin help

创建仓储

#   新建一个空文件夹,这里是:/home/ddz/1-code/svn/repository
#   如果文件非空,会报错
#	不用 sudo 也可以
sudo svnadmin create /home/ddz/1-code/svn/repository
sudo chmod 777 -R /home/ddz/1-code/svn/repository
            

svnadmin create 创建仓储之新建文件夹

svnadmin create 创建仓储

svnadmin create 创建仓储之后修改访问权限

配置仓储

配置文件在仓储目录中的conf目录下,主要是svnserve.confpasswdauthz这三个文件

passwd

在这里配置用户民和密码

[users]
# harry = harryssecret
# sally = sallyssecret
all1 = all1666
all2 = all2666
f1 = f1666
f2 = f2666
b1 = b1666
b2 = b2666
            
authz

在这里配置哪些用户可以可读、可写哪些目录,支持根据角色授权


[groups]
all = all1,all2
f = f1,f2
b = b1,b2

[/]
@all = rw
* = r

[/python]
@all = rw
@b = rw
@f = r
* = r

[/web]
@all = rw
@f = rw
@b = r
* = r
            
svnserve.conf

这里应该算是仓储的入口配置文件,其中 password-db 指向上面的 passwd 文件,authz-db 指向上面的 authz 文件

[general]
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
            

svnadmin create 创建仓储之后 passwd、authz 和 svnserve.conf 文件配置

svnserve.conf文件中已经包括了上面的四个配置,只不过是注释掉的,你只需放开注释即可

如果你也有这样的习惯:原来的配置文件不动,将这些添加到最后。你一定要注意,这四个配置属于[general];如果你添加到了文件的末尾,那就找错组织了,[sasl]并不知道他们

svnadmin create 创建仓储之后 svnserve.conf 文件配置

踩坑记录

这里是错误的示范,svnserve.conf文件的配置如下图:

svnserve.conf 错误配置示例

在这种配置之下,用户获取代码时,不用输入用户名和密码,直接可以获取代码。当然,想要修改之后签入代码也是不可能的

svnserve.conf 错误配置下,客户端拉取代码1

svnserve.conf 错误配置下,客户端拉取代码2

svn import 的项目的结构

导入项目

导入两个示例项目:基于 fastapi 的 python 项目和前端类库 a2bei4 项目。代码给你准备好了,你可以点击下载:fastapi-demoa2bei4

svn import /home/ddz/桌面/fastapi-demo file:///home/ddz/1-code/svn/repository/python/fastapi-demo -m "添加一个 Python 项目"

svn import /home/ddz/桌面/a2bei4 file:///home/ddz/1-code/svn/repository/web/a2bei4 -m "添加前端项目 a2bei4"
            

svn import 导入一下初始项目

启动

参考:SVN 启动模式 | 菜鸟教程

svnserve -d -r /home/ddz/1-code/svn/repository --listen-port 3690

#   查看服务
ps -ef | grep svnserve
#   干掉他
killall svnserve
            

单库 svnserve 方式启动

到这里,客户端再次尝试拉取代码就能弹出认证的弹窗了

客户端拉取代码,可以弹出认证弹窗

客户端

windows

这里选择的是TortoiseSVN,对就是那个可爱的小乌龟……

首次安装

敬请期待……

更改已安装

之所以出现这种情况是:在命令行使用 svn 或者写一些 *.bat 批处理时(例如:svn update)并且在安装小乌龟时没有选择安装command line client tools,此时需要修改安装一下。

如果安装时没有选择command line client tools,在 cmd 命令行无法使用 svn ,会提示“'svn' 不是内部或外部命令,也不是可运行的程序或批处理文件。”

点击查看详细的安装步骤

修改程序 TortoiseSVN 之点击更改

修改程序 TortoiseSVN 之首页

修改程序 TortoiseSVN 之选择更改类型

修改程序 TortoiseSVN 之选择安装 command line client tools

修改程序 TortoiseSVN 之选择安装 command line client tools 完成

修改程序 TortoiseSVN 之 Ready to Install

修改程序 TortoiseSVN 之选择已安装 TortoiseSVN 版本的 exe 文件

修改程序 TortoiseSVN 之选择已安装 TortoiseSVN 版本的 exe 文件,管理员权限确认

修改程序 TortoiseSVN 之更改完成,cmd 命令行 检查 svn

实战

.bat 获取更新、安装依赖、构建

测试的项目是:前端类库 a2bei4 。上面已经提到。这里分别在两个文件夹都拉去了上文中初始化的基于 fastapi 的 python 项目和前端类库 a2bei4 项目,来模拟两个用户,一个用户修改 a2bei4 项目,另一个用户执行 .bat 文件(拉取更新、安装依赖和构建)

在两个文件夹用两个用户获取同一个SVN仓储

点击查看 .bat 文件内容
@echo off
setlocal


:: 1、进入项目目录

cd /d E:\DDZ\svn\user2\web\a2bei4


:: 2、拉取更新

:: 		时间戳
set "timestamp=%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%%time:~9,2%"
set "timestamp=%timestamp: =0%"

:: 		开始拉取更新并将输出信息写入到 *.txt 临时文件 
svn update . > "%timestamp%.txt"


:: 3、更新中是否包含 package.json 文件

:: 		读取文件并逐行判断,如果存在,直接跳出循环
set "PACKAGE_JSON_CHANGED=false"
for /f "delims=" %%a in ('type "%timestamp%.txt"') do (
    if /i "%%a" neq "" (
        echo %%a | findstr /i "package.json" >nul && (
            set PACKAGE_JSON_CHANGED=true
            goto :check_done
        )
    )
)
:check_done


:: 		删除 *.txt 临时文件 
del /q "%timestamp%.txt"


:: 4、根据 package.json 是否被修改执行相应操作
if "%PACKAGE_JSON_CHANGED%" == "true" (
    echo 》》》》》》 package.json has changed. Cleaning up...
	
    if exist node_modules (
        echo 》》》》》》 node_modules exists. delete node_modules...
        rd /s /q node_modules
    )
	
    echo 》》》》》》 Installing dependencies...
    call npm install
    echo 》》》》》》 build project...
    call npm run c
) else (
    echo package.json has not changed.
    if not exist node_modules (
        echo 》》》》》》 node_modules does not exist. Installing dependencies...
        call npm install
        echo 》》》》》》 build project...
        call npm run c
    ) else (
        echo 》》》》》》 node_modules exists. build project...
        call npm run c
    )
)


echo.
pause
endlocal
                

post-commit

这个钩子还是挺重要的,好多都是从他这里触发的

HTTP 请求

用户提交更新之后,这里稍作判断,发送 HTTP 请求通知Jenkins构建

REPOS="$1"
REV="$2"
TXN_NAME="$3"

LOG_FILE="/home/ddz/1-code/svn/repository/log/post-commit.log" # 定义日志文件路径

# 记录提交信息到日志文件
echo "》》》》》》监听到提交,信息如下:" >> $LOG_FILE
echo "REPOS: $REPOS" >> $LOG_FILE
echo "REV: $REV" >> $LOG_FILE
echo "TXN_NAME: $TXN_NAME" >> $LOG_FILE
echo " " >> $LOG_FILE

# 遍历提交的文件列表并记录到日志文件
echo "变化的文件如下:" >> $LOG_FILE
svnlook changed -r $REV $REPOS >> $LOG_FILE
echo " " >> $LOG_FILE

# 检查本次提交中是否包含 vue 项目的变更
if svnlook changed -r $REV $REPOS | grep 'web/a2bei4'; then
# 使用 cURL 发送 GET 请求通知 Jenkins 构建 a2bei4 项目
echo "Calling Jenkins to build a2bei4..." >> $LOG_FILE
curl -u admin:admin666 -X GET http://192.168.xxx.xxx:9966/job/task-001/build?token=user2-a2bei4 >> $LOG_FILE
fi
echo " " >> $LOG_FILE
echo " " >> $LOG_FILE
echo " " >> $LOG_FILE
            

执行 python 脚本

一些简单的逻辑放在post-commit还行,如果逻辑比较复杂,至少咱写着就有些吃力了。可以中转一下,暂且叫做中枢,可能是一个 python 脚本,也可能是一个 HTTP 请求(这里的不是指的 Jenkins 的构建API哦)……post-commit将已知的所有数据作为参数传给中枢,之后由中枢去做复杂的逻辑判断

下面是post-commit中的主要内容

REPOS="$1"
REV="$2"
TXN_NAME="$3"
SVN_CHANGED=$(svnlook changed -r $REV $REPOS)

# 执行 Python 脚本并传递参数
python3 /home/ddz/1-code/svn-post-commit/main.py "$REPOS" "$REV" "$TXN_NAME" "$SVN_CHANGED"
            

需要注意一下:python3能不能找到

在看一下 python 脚本的内容

import os
import sys
import time
import datetime

# 接收参数
REPOS = sys.argv[1]
REV = sys.argv[2]
TXN_NAME = sys.argv[3]
SVN_CHANGED = sys.argv[4]

log_list = [
    f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')} 》》》》》》监听到提交,信息如下:\n",
    f"REPOS :{REPOS}\n",
    f"REV :{REV}\n",
    f"TXN_NAME :{TXN_NAME}\n",
    "变更的文件列表:\n",
    str(SVN_CHANGED)
]

timestamp = time.time()
file_name = str(int(timestamp)) + ".txt"
file_path = os.path.dirname(os.path.abspath(__file__)) + "/" + file_name
with open(file_path,"w",encoding='utf-8') as f:
    f.writelines(log_list)
            

这里为了方便测试,直接将 *.txt 文件放在同一目录了,需要注意一下,该目录是否有写入权限

在两个文件夹用两个用户获取同一个SVN仓储