# 思路
- 使用
Github Pages
的静态站点托管服务生成一个网站,这个网站只有简单的功能,上传文件到中转站。 - 这个中转站就是暂时存储文件,我们使用
Leancloud
的能力,提供开放api支持存储。 - 使用
Github Actions
能力,每日定时获取中转站的文件,然后上传到当前仓库下。
# 步骤
- 创建leancloud (opens new window)账号,然后创建一个应用,拿到appId和appKey。根据文档 (opens new window)可以看到,
Leancloud
提供了js
的sdk,我们使用这个sdk来操作文件,实现思路中的步骤1和步骤2。示例如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Upload to Github</title>
<script src="https://unpkg.com/leancloud-storage@4.15.2/dist/av-min.js"></script>
<style>
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
margin: 20px;
text-align: center;
}
h1 {
color: #333;
}
.upload-container {
margin-top: 30px;
padding: 20px;
}
.custom-file-upload {
display: inline-block;
padding: 12px 24px;
cursor: pointer;
border-radius: 4px;
background-color: #5cb85c;
color: white;
border: 1px solid transparent;
transition: all 0.3s ease-in-out;
}
.custom-file-upload:hover {
background-color: #4cae4c;
}
#file-input {
display: none; /* Hide the default file input */
}
/* Responsive adjustments */
@media (max-width: 768px) {
.upload-container {
padding: 15px;
}
.custom-file-upload {
padding: 10px 20px; /* Slightly smaller padding on mobile */
}
}
</style>
<script>
// 初始化 LeanCloud 应用
AV.init({
appId: "appId", // 替换为你的 App ID
appKey: "appKey", // 替换为你的 App Key
serverURL: "https://cn-n1-console-api.leancloud.cn", // 替换为你的 Server URL
});
// 文件上传函数
function uploadFile(fileInput) {
if (fileInput.files.length > 0) {
// 遍历所有选择的文件
Array.from(fileInput.files).forEach((file) => {
// 检查文件大小(20MB)
if (file.size <= 20 * 1024 * 1024) {
// 创建 LeanCloud File 对象
const leanFile = new AV.File(file.name, file);
// 保存文件到 LeanCloud
leanFile
.save()
.then((file) => {
console.log(`File uploaded successfully: ${file.url()}`);
})
.catch((error) => {
alert(`Error uploading file: ${error}`);
});
} else {
alert(`${file.name} is too large. Limit is 20MB.`);
}
});
}
}
// 手动触发文件选择框
function triggerFileInput() {
document.getElementById("file-input").click();
}
</script>
</head>
<body>
<h1>上传至github仓库</h1>
<div class="upload-container">
<label for="file-input" class="custom-file-upload"> 选择文件 </label>
<input type="file" id="file-input" onchange="uploadFile(this)" multiple />
</div>
</body>
</html>
- 创建一个js文件,用于读取leancloud中转站的文件,然后将文件上传到github仓库。
tips:需要在当前目录下创建downloaded文件夹
const fs = require('fs');
const https = require('https');
const { execSync } = require('child_process');
const AV = require("leancloud-storage");
// 初始化 LeanCloud 应用
AV.init({
appId: "appId", // 替换为你的 App ID
appKey: "appKey", // 替换为你的 App Key
serverURL: "https://cn-n1-console-api.leancloud.cn", // 替换为你的 Server URL
});
// 辅助函数下载文件
const downloadFile = (url, outputPath) => {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(outputPath);
https.get(url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close(resolve);
});
}).on('error', (err) => {
fs.unlink(outputPath); // 删除文件
reject(err.message);
});
});
};
function getFiles() {
// 获取文件
return new Promise((resolve, reject) => {
const query = new AV.Query('_File');
query.find().then((nodes) => {
const files = nodes.map(node => {
return {
url: node.get('url'),
name: node.get('name')
}
});
resolve(files);
}).catch((error) => {
reject(error);
console.error('获取文件失败', error);
});
})
}
async function init() {
const fileUrls = await getFiles();
// 下载所有文件
await Promise.all(
fileUrls.map(({ url, name }) => {
// 提取文件名,并定义本地下载路径
const fileName = url.split('/').pop();
const outputPath = `./downloaded/${name || fileName}`;
const realUrl = url.replace('http://', 'https://');
return downloadFile(realUrl, outputPath);
})
)
.then(() => {
// 所有文件下载完成后进行提交
execSync('git config --local user.name "Zgrowth"');
execSync('git config --local user.email "18296884762@163.com"');
execSync('git add downloaded/*');
execSync(`git commit -m "Add downloaded files ${new Date().getTime()}"`);
execSync('git push');
// 文件上传到仓库后将中转站的文件全部删除
deleteClassData();
})
.catch((error) => {
console.error('Error downloading files:', error);
});
}
function deleteClassData() {
const query = new AV.Query('_File');
query.find().then((results) => {
// 创建一个删除操作的数组
const deletes = results.map(item => {
return AV.Object.createWithoutData('_File', item.id).destroy();
});
// 并发执行所有删除操作
return Promise.all(deletes);
}).then(() => {
console.log('全部数据已被删除。');
}).catch((err) => {
console.error('删除过程中出现错误:', err);
});
}
init();
由于上面js文件使用到了leancloud-storage包,所以需要package.json
// package.json
{
"name": "z-file",
"version": "1.0.0",
"description": "",
"main": "download-and-commit.js",
"scripts": {
"start": "node ./download-and-commit.js"
},
"keywords": [],
"author": "zs",
"license": "ISC",
"dependencies": {
"leancloud-storage": "^4.15.2"
}
}
- 使用github action 定时触发,并执行上述js文件
name: Download and Commit Files
on:
workflow_dispatch: # 手动触发
# 定时器 github服务器时间比北京时间晚8小时 定时早上6点执行
schedule:
- cron: '0 16 * * *'
jobs:
download-and-commit:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: npm install
run: npm install
- name: Download files and commit
run: npm start
# 解决没有足够的权限来推送文件到你的仓库
当 GitHub Actions 报告 "Permission to user/repo.git denied to github-actions[bot]" 错误时,这意味着尝试使用的 GitHub Token 没有足够的权限来推送到你的仓库。其中一个常见原因是尝试推送到一个受保护的分支,GitHub 默认的 GITHUB_TOKEN 没有权限执行这样的操作。
解决这个问题的方法之一是在仓库的 "Settings" -> "Secrets" 中添加一个有足够权限的 Personal Access Token (PAT),然后在你的 GitHub Actions 工作流中使用这个 PAT。
步骤如下:
1. 生成 Personal Access Token:
前往 GitHub -> Settings -> Developer settings -> Personal access tokens -> Generate new token。确保给予 token repo 范围的权限,以便它可以访问你的仓库。
2. 添加 PAT 到 GitHub 仓库的 Secrets:
前往仓库的 Settings -> Secrets -> New repository secret。添加一个名称(例如 REPO_ACCESS_TOKEN),粘贴你的 Personal Access Token。
3. 修改你的 GitHub Actions 工作流文件:
更新你的工作流文件(.github/workflows/your-workflow.yml),在相应步骤中使用这个新的 secret 来做身份验证。例如:
jobs:
push-commit:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }} # 使用你的 Personal Access Token 代替默认的 GITHUB_TOKEN
# 其他配置...
# ... 其它步骤 ...