modify: Docker 部署脚本更新
This commit is contained in:
+57
@@ -0,0 +1,57 @@
|
||||
FROM debian:bookworm-slim AS builder
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY build/chongming /tmp/chongming
|
||||
|
||||
RUN mkdir -p /tmp/rootfs/app && \
|
||||
# === 临时目录 ===
|
||||
mkdir -p /tmp/rootfs/tmp && \
|
||||
chmod 1777 /tmp/rootfs/tmp && \
|
||||
# === 数据目录 ===
|
||||
mkdir -p /tmp/rootfs/app/data && \
|
||||
chmod 777 /tmp/rootfs/app/data && \
|
||||
# === 解释器目录 ===
|
||||
mkdir -p /tmp/rootfs/lib64 && \
|
||||
mkdir -p /tmp/rootfs/lib/x86_64-linux-gnu && \
|
||||
cp /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
ln -s /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2 && \
|
||||
# === 依赖库 ===
|
||||
cp /lib/x86_64-linux-gnu/libdl.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libz.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libpthread.so.0 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/librt.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libm.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libutil.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
|
||||
cp /lib/x86_64-linux-gnu/libnss_dns.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
|
||||
cp /lib/x86_64-linux-gnu/libnss_files.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
|
||||
cp /lib/x86_64-linux-gnu/libresolv.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
|
||||
# === 时区数据 ===
|
||||
mkdir -p /tmp/rootfs/usr/share/zoneinfo && \
|
||||
cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ && \
|
||||
cp /usr/share/zoneinfo/UTC /tmp/rootfs/usr/share/zoneinfo/ && \
|
||||
# === 证书和 DNS ===
|
||||
mkdir -p /tmp/rootfs/etc/ssl/certs && \
|
||||
cp /etc/ssl/certs/ca-certificates.crt /tmp/rootfs/etc/ssl/certs/ && \
|
||||
echo "hosts: files dns" > /tmp/rootfs/etc/nsswitch.conf && \
|
||||
# === /proc /sys /dev ===
|
||||
mkdir -p /tmp/rootfs/proc /tmp/rootfs/sys /tmp/rootfs/dev
|
||||
|
||||
FROM scratch
|
||||
|
||||
COPY --from=builder /tmp/rootfs/ /
|
||||
|
||||
COPY build/chongming /app/chongming
|
||||
COPY build/config.toml /app/config.toml
|
||||
COPY build/resources/ /app/resources/
|
||||
COPY build/static.svfs /app/static.svfs
|
||||
COPY build/data /app/data
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["./chongming"]
|
||||
@@ -76,9 +76,6 @@ docker load -i chongming_latest.tar
|
||||
|
||||
运行镜像
|
||||
```shell
|
||||
mkdir -p /data/chongming
|
||||
docker run -d -p 8000:8000 \
|
||||
-v /data/chongming/database.db:/app/database.db \
|
||||
-v /data/chongming/uploads:/app/uploads \
|
||||
--name chongming chongming:latest
|
||||
sudo chmod 777 ./deploy.sh
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
+28
-28
@@ -1,27 +1,27 @@
|
||||
[default]
|
||||
app.debug = false
|
||||
app.description = "基于 FastAPI 的 chongming 打包脚手架"
|
||||
app.name = "chongming"
|
||||
app.version = "chongming"
|
||||
app.description = "基于 FastAPI 的 chongming 打包脚手架"
|
||||
app.debug = false
|
||||
env = "development"
|
||||
prefix = "/api/v1"
|
||||
upload_path = "uploads"
|
||||
|
||||
[database]
|
||||
database_path = "./data/database.db"
|
||||
type = "sqlite"
|
||||
url = "sqlite+aiosqlite:///./database.db"
|
||||
generate_schemas = true # 生产环境使用迁移工具
|
||||
url = "sqlite+aiosqlite:///./data/database.db"
|
||||
|
||||
[database.sqlite]
|
||||
connect_args.check_same_thread = false
|
||||
connect_args.timeout = 15
|
||||
echo = true
|
||||
echo_pool = true
|
||||
pool_size = 20
|
||||
max_overflow = 10
|
||||
pool_timeout = 30
|
||||
pool_recycle = 300
|
||||
pool_pre_ping = true
|
||||
connect_args.timeout = 15
|
||||
connect_args.check_same_thread = false
|
||||
pool_recycle = 300
|
||||
pool_size = 20
|
||||
pool_timeout = 30
|
||||
|
||||
[scheduler]
|
||||
job_store_path = "scheduler_jobs.db"
|
||||
@@ -30,61 +30,61 @@ job_store_path = "scheduler_jobs.db"
|
||||
cache_store_path = "./"
|
||||
|
||||
[security]
|
||||
secret_key = "your-secret-key-change-in-production"
|
||||
algorithm = "HS256"
|
||||
access_token_expire_minutes = 30
|
||||
refresh_token_expire_days = 7
|
||||
algorithm = "HS256"
|
||||
max_sessions_per_user = 5
|
||||
refresh_token_expire_days = 7
|
||||
secret_key = "your-secret-key-change-in-production"
|
||||
|
||||
[development]
|
||||
env = "development"
|
||||
debug = true
|
||||
env = "development"
|
||||
|
||||
[development.server]
|
||||
access_log = false
|
||||
host = "127.0.0.1"
|
||||
port = 8000
|
||||
reload = true
|
||||
access_log = false
|
||||
|
||||
[development.logging]
|
||||
level = "DEBUG"
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
level = "DEBUG"
|
||||
|
||||
[development.cors]
|
||||
allow_origins = ["*"]
|
||||
allow_credentials = true
|
||||
allow_methods = ["*"]
|
||||
allow_headers = ["*"]
|
||||
allow_methods = ["*"]
|
||||
allow_origins = ["*"]
|
||||
|
||||
[production]
|
||||
env = "production"
|
||||
debug = false
|
||||
env = "production"
|
||||
|
||||
[production.server]
|
||||
access_log = false
|
||||
host = "0.0.0.0"
|
||||
port = 8000
|
||||
reload = false
|
||||
workers = 4
|
||||
access_log = false
|
||||
|
||||
[production.logging]
|
||||
level = "INFO"
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
max_size = 10485760 # 10MB
|
||||
backup_count = 5 # 最多保存 10 个日志文件
|
||||
backup_count = 5 # 最多保存 10 个日志文件
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
level = "INFO"
|
||||
max_size = 10485760 # 10MB
|
||||
|
||||
[production.cors]
|
||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
allow_credentials = true
|
||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
||||
allow_headers = ["Authorization", "Content-Type"]
|
||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
|
||||
[production.module_system]
|
||||
type = "module-bank"
|
||||
path = ["resources/app.mbank", "resources/plugins.mbank"]
|
||||
type = "module-bank"
|
||||
|
||||
[production.file_system]
|
||||
type = "svfs"
|
||||
path = "static.svfs"
|
||||
type = "svfs"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
# deploy.sh - chongming 快速部署脚本
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# 配置
|
||||
IMAGE="chongming:latest"
|
||||
CONTAINER="chongming"
|
||||
PORT=8000
|
||||
DATA_DIR="${HOME}/chongming-data"
|
||||
|
||||
# 检查 docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker 未安装,请先安装 Docker"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查镜像
|
||||
if ! docker image inspect "$IMAGE" &> /dev/null; then
|
||||
log_error "镜像 $IMAGE 不存在,请先构建: docker build -t $IMAGE ."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. 停止并删除旧容器
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
|
||||
log_warn "发现旧容器,正在停止并删除..."
|
||||
docker stop "$CONTAINER" 2>/dev/null || true
|
||||
docker rm "$CONTAINER" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 2. 创建目录
|
||||
log_info "创建数据目录..."
|
||||
mkdir -p "$DATA_DIR"/{data,uploads,logs}
|
||||
chmod 755 "$DATA_DIR"/{data,uploads,logs}
|
||||
|
||||
# 3. 复制初始数据(仅在目录为空时)
|
||||
if [ -z "$(ls -A $DATA_DIR/data 2>/dev/null)" ]; then
|
||||
log_info "首次部署,从镜像中提取初始数据库..."
|
||||
TMP_CONTAINER="chongming-tmp-$$"
|
||||
docker create --name "$TMP_CONTAINER" "$IMAGE" &> /dev/null
|
||||
docker cp "$TMP_CONTAINER:/app/data/." "$DATA_DIR/data/" &> /dev/null
|
||||
docker rm "$TMP_CONTAINER" &> /dev/null
|
||||
log_info "初始数据库已就绪"
|
||||
else
|
||||
log_info "数据库已存在,跳过初始化"
|
||||
fi
|
||||
|
||||
# 检查端口是否被占用
|
||||
if ss -tlnp | grep -q ":${PORT}"; then
|
||||
log_error "端口 ${PORT} 已被占用,请修改 PORT 变量或释放端口"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. 启动容器
|
||||
log_info "启动容器..."
|
||||
docker run -d \
|
||||
-p "$PORT:8000" \
|
||||
-v "$DATA_DIR/data:/app/data" \
|
||||
-v "$DATA_DIR/uploads:/app/uploads" \
|
||||
-v "$DATA_DIR/logs:/app/logs" \
|
||||
--restart unless-stopped \
|
||||
--name "$CONTAINER" \
|
||||
"$IMAGE"
|
||||
|
||||
# 5. 等待启动
|
||||
log_info "等待应用启动..."
|
||||
sleep 3
|
||||
|
||||
# 6. 检查状态
|
||||
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
|
||||
log_info "=========================================="
|
||||
log_info "✅ 部署成功!"
|
||||
log_info "=========================================="
|
||||
log_info "应用地址: http://localhost:$PORT"
|
||||
log_info "API 文档: http://localhost:$PORT/docs"
|
||||
log_info "数据目录: $DATA_DIR"
|
||||
log_info ""
|
||||
log_info "查看日志: docker logs -f $CONTAINER"
|
||||
log_info "停止服务: docker stop $CONTAINER"
|
||||
log_info "重启服务: docker restart $CONTAINER"
|
||||
log_info "=========================================="
|
||||
else
|
||||
log_error "容器启动失败,查看日志:"
|
||||
docker logs "$CONTAINER" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
# 使用 Debian 的极简版,确保有基础的 glibc(推荐)
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# 可选:设置时区、安装 ca-certificates 等
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制打包好的可执行文件
|
||||
COPY build/chongming /app/
|
||||
|
||||
# 复制运行时需要的静态资源、配置文件、.mbank 等
|
||||
COPY build/config.toml /app/
|
||||
COPY build/resources/ /app/resources/
|
||||
COPY build/static.svfs /app/
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8000
|
||||
|
||||
# 启动
|
||||
CMD ["./chongming"]
|
||||
+30
-30
@@ -1,27 +1,27 @@
|
||||
[default]
|
||||
app.debug = false
|
||||
app.description = "基于 FastAPI 的 chongming 打包脚手架"
|
||||
app.name = "chongming"
|
||||
app.version = "0.1.0"
|
||||
app.description = "基于 FastAPI 的 chongming 打包脚手架"
|
||||
app.debug = false
|
||||
env = "production"
|
||||
prefix = "/api/v1"
|
||||
upload_path = "uploads"
|
||||
|
||||
[database]
|
||||
type = "sqlite"
|
||||
url = "sqlite+aiosqlite:///./database.db"
|
||||
generate_schemas = true # 生产环境使用迁移工具
|
||||
generate_schemas = true # 生产环境使用迁移工具
|
||||
type = "sqlite"
|
||||
url = "sqlite+aiosqlite:///./data/database.db"
|
||||
|
||||
[database.sqlite]
|
||||
connect_args.check_same_thread = false
|
||||
connect_args.timeout = 15
|
||||
echo = false
|
||||
echo_pool = false
|
||||
pool_size = 20
|
||||
max_overflow = 10
|
||||
pool_timeout = 30
|
||||
pool_recycle = 300
|
||||
pool_pre_ping = true
|
||||
connect_args.timeout = 15
|
||||
connect_args.check_same_thread = false
|
||||
pool_recycle = 300
|
||||
pool_size = 20
|
||||
pool_timeout = 30
|
||||
|
||||
[scheduler]
|
||||
job_store_path = "scheduler_jobs.db"
|
||||
@@ -30,62 +30,62 @@ job_store_path = "scheduler_jobs.db"
|
||||
cache_store_path = "./"
|
||||
|
||||
[security]
|
||||
secret_key = "your-secret-key-change-in-production"
|
||||
algorithm = "HS256"
|
||||
access_token_expire_minutes = 30
|
||||
refresh_token_expire_days = 7
|
||||
algorithm = "HS256"
|
||||
max_sessions_per_user = 5
|
||||
refresh_token_expire_days = 7
|
||||
secret_key = "your-secret-key-change-in-production"
|
||||
|
||||
[development]
|
||||
env = "development"
|
||||
debug = true
|
||||
env = "development"
|
||||
|
||||
[development.server]
|
||||
access_log = false
|
||||
host = "127.0.0.1"
|
||||
port = 8001
|
||||
reload = true
|
||||
access_log = false
|
||||
|
||||
[development.logging]
|
||||
level = "DEBUG"
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
level = "DEBUG"
|
||||
|
||||
[development.cors]
|
||||
allow_origins = ["*"]
|
||||
allow_credentials = true
|
||||
allow_methods = ["*"]
|
||||
allow_headers = ["*"]
|
||||
allow_methods = ["*"]
|
||||
allow_origins = ["*"]
|
||||
|
||||
[production]
|
||||
env = "production"
|
||||
debug = false
|
||||
env = "production"
|
||||
|
||||
[production.server]
|
||||
access_log = false
|
||||
host = "0.0.0.0"
|
||||
port = 8000
|
||||
reload = false
|
||||
workers = 4
|
||||
access_log = false
|
||||
timeout_keep_alive = 65
|
||||
workers = 4
|
||||
|
||||
[production.logging]
|
||||
level = "INFO"
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
max_size = 10485760 # 10MB
|
||||
backup_count = 5 # 最多保存 10 个日志文件
|
||||
backup_count = 5 # 最多保存 10 个日志文件
|
||||
file = "logs"
|
||||
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
level = "INFO"
|
||||
max_size = 10485760 # 10MB
|
||||
|
||||
[production.cors]
|
||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
allow_credentials = true
|
||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
||||
allow_headers = ["Authorization", "Content-Type"]
|
||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
|
||||
[production.module_system]
|
||||
type = "module-bank"
|
||||
path = ["resources/app.mbank", "resources/plugins.mbank"]
|
||||
type = "module-bank"
|
||||
|
||||
[production.file_system]
|
||||
type = "svfs"
|
||||
path = "static.svfs"
|
||||
type = "svfs"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 204 KiB |
@@ -14,10 +14,10 @@ import { useAuthStore } from './stores/auth'
|
||||
/**
|
||||
* 打包时取消该注释
|
||||
*/
|
||||
import { client } from "./api/generated/client.gen"
|
||||
client.setConfig({
|
||||
baseUrl: "/"
|
||||
})
|
||||
// import { client } from "./api/generated/client.gen"
|
||||
// client.setConfig({
|
||||
// baseUrl: "/"
|
||||
// })
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
})
|
||||
@@ -64,8 +64,12 @@ async def lifespan(app: FastAPI):
|
||||
database_config = database.get(database_type, None)
|
||||
if database_config is None:
|
||||
raise ValueError("配置不存在")
|
||||
database_path = database.get("database_path", None)
|
||||
if database_path:
|
||||
Path(database_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
engine_config = {k: v for k, v in database_config.items() if k != "database_path"}
|
||||
|
||||
engine = create_async_engine(database["url"], **database_config)
|
||||
engine = create_async_engine(database["url"], **engine_config)
|
||||
async_session_maker = async_sessionmaker(
|
||||
engine, class_=AsyncSession, expire_on_commit=False
|
||||
)
|
||||
|
||||
@@ -60,6 +60,7 @@ class Database(TypedDict, total=False):
|
||||
sqlite: DatabaseSqlite
|
||||
mysql: dict
|
||||
postgresql: dict
|
||||
database_path: str
|
||||
|
||||
|
||||
class Security(TypedDict):
|
||||
|
||||
@@ -134,6 +134,10 @@ def run_pyinstaller():
|
||||
"-m",
|
||||
"PyInstaller",
|
||||
"--onefile",
|
||||
"--noconfirm",
|
||||
"--optimize",
|
||||
"2",
|
||||
"--strip",
|
||||
"--name",
|
||||
"chongming",
|
||||
"--distpath",
|
||||
@@ -173,11 +177,7 @@ def run_pyinstaller():
|
||||
"--hidden-import",
|
||||
"diskcache",
|
||||
"--hidden-import",
|
||||
"passlib",
|
||||
"--hidden-import",
|
||||
"passlib.context",
|
||||
"--hidden-import",
|
||||
"passlib.handlers.bcrypt",
|
||||
"bcrypt",
|
||||
"--hidden-import",
|
||||
"sqlite_vfs",
|
||||
"--hidden-import",
|
||||
@@ -197,6 +197,10 @@ def run_pyinstaller():
|
||||
"-m",
|
||||
"PyInstaller",
|
||||
"--onefile",
|
||||
"--noconfirm",
|
||||
"--optimize",
|
||||
"2",
|
||||
"--strip",
|
||||
"--name",
|
||||
"chongming",
|
||||
"--distpath",
|
||||
@@ -236,11 +240,7 @@ def run_pyinstaller():
|
||||
"--hidden-import",
|
||||
"diskcache",
|
||||
"--hidden-import",
|
||||
"passlib",
|
||||
"--hidden-import",
|
||||
"passlib.context",
|
||||
"--hidden-import",
|
||||
"passlib.handlers.bcrypt",
|
||||
"bcrypt",
|
||||
"--hidden-import",
|
||||
"sqlite_vfs",
|
||||
"--hidden-import",
|
||||
@@ -309,9 +309,9 @@ async def init_database():
|
||||
database_config = database.get(database_type, None)
|
||||
if database_config is None:
|
||||
raise ValueError("配置不存在")
|
||||
|
||||
os.makedirs("./build/data", exist_ok=True)
|
||||
engine = create_async_engine(
|
||||
"sqlite+aiosqlite:///./build/database.db", **database_config
|
||||
"sqlite+aiosqlite:///./build/data/database.db", **database_config
|
||||
)
|
||||
async_session_maker = async_sessionmaker(
|
||||
engine, class_=AsyncSession, expire_on_commit=False
|
||||
|
||||
@@ -22,7 +22,8 @@ def generate_markdown_from_py_files(directory, output_file):
|
||||
or file.endswith(".ts")
|
||||
or file.endswith(".json")
|
||||
or file.endswith(".html")
|
||||
or file == "dockerfile"
|
||||
or file.endswith(".sh")
|
||||
or file == "Dockerfile"
|
||||
):
|
||||
file_path = os.path.join(root, file)
|
||||
if file == "output.md" or file == "package-lock.json":
|
||||
|
||||
Reference in New Issue
Block a user