import os
import time
import subprocess
import schedule
from datetime import datetime
import paramiko
from dateutil import parser
def read_last_build_time():
"""
读取上次打包的时间
:return: 上次打包的时间(datetime对象),如果文件不存在则返回None
"""
try:
with open(LAST_BUILD_TIME_FILE, "r") as f:
return datetime.fromisoformat(f.read().strip())
except FileNotFoundError:
return None
def write_last_build_time(time):
"""
写入本次打包的时间
:param time: 当前时间(datetime对象)
"""
with open(LAST_BUILD_TIME_FILE, "w") as f:
f.write(time.isoformat())
def git_pull():
"""
执行git pull命令,拉取最新代码
"""
subprocess.run(["git", "pull"], cwd=REPO_DIR, check=True, stdout=subprocess.DEVNULL)
def get_last_commit_time():
"""
获取仓库中最新一次提交的时间
:return: 最新一次提交的时间(datetime对象)
"""
result = subprocess.run(["git", "log", "-1", "--format=%cd", "--date=iso"], cwd=REPO_DIR, capture_output=True,
text=True, check=True)
return parser.parse(result.stdout.strip())
def build_project():
"""
执行打包命令,构建项目
"""
subprocess.run(["pnpm", "i"], cwd=REPO_DIR, shell=True, check=True, stdout=subprocess.DEVNULL)
subprocess.run(["pnpm", "run", "build"], cwd=REPO_DIR, shell=True, check=True, stdout=subprocess.DEVNULL)
def rename_remote_dirs(ssh):
"""
判断远程目录并重命名
"""
try:
new_dir = os.path.join(os.path.dirname(REMOTE_DIR), datetime.now().strftime("%Y%m%d%H%M"))
new_dir = new_dir.replace("\\", "/").replace(r"\\", "/")
ssh.exec_command(f"mv {REMOTE_DIR} {new_dir}")
except IOError:
pass
ssh.exec_command(f"mv {REMOTE_DIR_TEMP} {REMOTE_DIR}")
def upload_build():
"""
上传打包生成的文件夹到远程服务器
"""
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(REMOTE_SERVER, port=REMOTE_PORT, username=REMOTE_USER, password=REMOTE_PASSWORD)
sftp = ssh.open_sftp()
for root, dirs, files in os.walk(BUILD_DIR):
for file in files:
local_path = os.path.join(root, file)
relative_path = os.path.relpath(local_path, BUILD_DIR)
remote_file = os.path.join(REMOTE_DIR_TEMP, relative_path).replace("\\", "/").replace(r"\\", "/")
remote_dir = os.path.dirname(remote_file)
try:
sftp.put(local_path, remote_file)
except FileNotFoundError:
ssh.exec_command(f"mkdir -p {remote_dir}")
except IOError:
pass
finally:
sftp.put(local_path, remote_file)
rename_remote_dirs(ssh)
sftp.close()
ssh.close()
def deploy():
"""
执行部署任务,包括:
1. 拉取最新代码
2. 检查是否有新提交
3. 如果有新提交,则构建项目并上传到远程服务器
"""
print(f"检查更新时间 {datetime.now()}")
git_pull()
last_build_time = read_last_build_time()
last_commit_time = get_last_commit_time().replace(tzinfo=None)
if last_build_time is None or last_commit_time > last_build_time:
print("检测到新提交,正在打包...")
build_project()
print("上传打包文件...")
upload_build()
write_last_build_time(datetime.now())
print("部署完成")
else:
print("没有检测到提交")
if __name__ == "__main__":
REPO_DIR = "D:/vue_test"
BUILD_DIR = os.path.join(REPO_DIR, "build")
REMOTE_SERVER = "your.server.ip"
REMOTE_PORT = 22
REMOTE_USER = "your_user"
REMOTE_PASSWORD = "your_password"
REMOTE_DIR = "/web/vue_test"
LAST_BUILD_TIME_FILE = "last_build_time.txt"
REMOTE_DIR_TEMP = os.path.join(os.path.dirname(REMOTE_DIR), 'temp').replace("\\", "/").replace(r"\\", "/")
deploy()
schedule.every(1).hours.do(deploy)
while True:
schedule.run_pending()
time.sleep(10)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!