[英]How to programatically create pull request with changed file using GitHub API
[英]How to commit a folder and open a Pull Request via Github API?
我想通过 Github API 为用户提交管道配置。
到目前为止,我只能将一个名为main.yaml
的文件提交到 repo 的根目录中,但我需要该文件位于.github/workflows/main.yaml
中。
到目前为止我的代码是这样的:
const commitWorkflowConfig = async ({
ownerName,
repoName
}) => {
const pipelineConfig = fs.readFileSync(__dirname + '/../../../templates/main.yaml', { encoding: "utf-8" })
// Create Blob from the content
const blob = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/blobs`, {
content: pipelineConfig,
encoding: "utf-8"
})
// Get last commit hash of Master
const {
commit: {
sha: masterSha
}
} = await axios.get(`https://api.github.com/repos/${ownerName}/${repoName}/branches/master`)
// Create new branch from master
const branch = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/refs`,
{
"ref": "refs/heads/workflow-pipeline",
"sha": masterSha
})
// Create commit to new branch
const commit = await axios.put(`https://api.github.com/repos/${ownerName}/${repoName}/contents/main.yaml`, {
message: "New commit",
content: pipelineConfig,
sha: blob.sha,
branch: "workflow-pipeline"
})
// Open Pull Request
const response = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/pulls`, {
title: "New PR",
head: "workflow-pipeline",
base: "master"
})
} const commitWorkflowConfig = async ({
ownerName,
repoName
}) => {
const pipelineConfig = fs.readFileSync(__dirname + '/../../../templates/main.yaml', { encoding: "utf-8" })
// Create Blob from the content
const blob = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/blobs`, {
content: pipelineConfig,
encoding: "utf-8"
})
// Get last commit hash of Master
const {
commit: {
sha: masterSha
}
} = await axios.get(`https://api.github.com/repos/${ownerName}/${repoName}/branches/master`)
// Create new branch from master
const branch = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/refs`,
{
"ref": "refs/heads/workflow-pipeline",
"sha": masterSha
})
// Create commit to new branch
const commit = await axios.put(`https://api.github.com/repos/${ownerName}/${repoName}/contents/main.yaml`, {
message: "New commit",
content: pipelineConfig,
sha: blob.sha,
branch: "workflow-pipeline"
})
// Open Pull Request
const response = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/pulls`, {
title: "New PR",
head: "workflow-pipeline",
base: "master"
})
}
这感觉就像很多 API 调用都是为了提交一个文件并打开一个 PR,我怀疑我做错了什么?
当我创建新的提交时,它不允许我添加任何路径或将.github/workflows/main.yaml
添加到 URL 的末尾,因为我得到了 404。有什么方法可以更新此提交以提交到文件夹而不是根目录?
总而言之,如何将.github/workflows/main.yaml
简单提交到新分支并为其打开 PR?
const tree = await this.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/trees`, {
base_tree: masterSha,
tree: [
{
path: ".github",
mode: "040000",
type: "tree"
},
{
path: ".github/workflow",
mode: "040000",
type: "tree"
},
{
path: ".github/workflow/main.yaml",
mode: "100755",
type: "tree",
content: pipelineConfig
},
]
})
const { tree } = await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/trees`, {
base_tree: masterSha,
tree: [
{
path: "workflows/main.yaml",
mode: "100644",
type: "blob",
sha
}
]
})
const workflowTree = tree.find(t => t.path === "workflows");
await axios.post(`https://api.github.com/repos/${ownerName}/${repoName}/git/trees`, {
base_tree: masterSha,
tree: [
{
path: ".github/workflows",
mode: workflowTree.mode, // "040000"
type: workflowTree.type, // "tree"
sha: workflowTree.sha
}
]
})
// Create commit to new branch
const commit = await axios.put(`https://api.github.com/repos/${ownerName}/${repoName}/contents/main.yaml`, {
message: "New commit",
content: pipelineConfig,
sha: blob.sha,
branch: "workflow-pipeline"
})
您不能直接编辑文件的内容。 您需要使用树 API 在原始树的基础上创建一棵全新的树。
为新文件创建 blob ( https://docs.github.com/en/rest/reference/git#create-a-blob )。 您已经很好地完成了这一步。
获取您想要创建新分支的树( https://docs.github.com/en/rest/reference/repos#get-a-branch )。 请注意,您必须获取树 sha ,而不是提交 sha 。
使用添加的文件创建一个新树 ( https://docs.github.com/en/rest/reference/git#create-a-tree )。 我认为这一步将是最复杂的,因为对于每个创建的“文件夹”树,还需要创建一个父“文件夹”树以包含新创建的“文件夹”树。 所以如果你想修改.github/workflows
文件夹,你首先必须创建一个基于.github/workflows
的新树。 比方说 tree sha 是abc...
然后,您需要基于.github
文件夹创建一棵新树,并将workflows
目录设为abc...
,而不是旧目录。
创建一个提交( https://docs.github.com/en/rest/reference/git#create-a-commit )。 使用您在上一步中创建的根树的 sha。
创建一个新分支 ( https://docs.github.com/en/rest/reference/git#create-a-reference )。 在问题代码中,您在创建提交之前创建了它,这是没有意义的。 您需要在创建提交后创建它,以便它的头部指向您创建的提交的 sha。
创建拉取请求 ( https://docs.github.com/en/rest/reference/pulls#create-a-pull-request )。 您的代码中已有此步骤。
这是一个视觉效果,解释了将main.yml
文件添加到.github/workflows
的步骤 2 和 3:
Original tree | New Tree (but the '.github' tree references ^b, not b)
- sha: a --> - sha: ^a
- files: - files:
- .github --> - .github (but the 'workflows' tree references ^c, not c)
- sha: b - sha: ^b
- files: - files
- workflows --> - workflows (but with the main.yml)
- sha: c - sha: ^c
- files: - files:
- main.yml (reference the sha of the blob you created)
...
...
...
视觉对象中有三个-->
。 每个-->
都是一个请求。
^c
树开始,它基于c
树并添加了main.yml
文件。^b
树,它基于b
但其中包含^c
。^a
树,它基于a
但其中包含^b
。 这些是创建
简单
但复杂的拉取请求的步骤。
令人惊讶的是为此需要多少次 API 调用。 5 + {你要添加的文件有多深}
我希望这可以帮助你,我正在研究同一个主题,我需要通过 API 更新.github/workflows
文件夹中的文件,我想我找到了一个更好更简单的方法。
我不知道从什么时候开始,但是,这个端点https://docs.github.com/en/rest/reference/repos#create-or-update-file-contents具有正确的权限(你的 authToken 中的范围workflow
) ,您可以在.github/workflows
文件夹中创建和更新文件。
// to create a new file
await octokit.request('PUT /repos/{owner}/{repo}/contents/{path}', {
owner: 'octocat',
repo: 'hello-world',
path: '.github/workflows/your-file.yml',
message: 'Your commit message',
content: 'contentInBase64'
});
// to update a file
// get the sha of the file that you want to update
const {
data: contentData
} = await octokit.request('GET /repos/{owner}/{repo}/contents/{path}', {
owner: 'octocat',
repo: 'hello-world',
path: '.github/workflows/your-file.yml',
});
const shaOfCurrentFileToUpdate = contentData.sha;
await octokit.request('PUT /repos/{owner}/{repo}/contents/{path}', {
owner: 'octocat',
repo: 'hello-world',
path: '.github/workflows/your-file.yml',
message: 'Your new commit message',
content: 'newContentInBase64'
sha: shaOfCurrentFileToUpdate
});
有了这个,我删除了很多代码行并解决了我这边的问题,希望对你也有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.