如何通过 Github API 提交文件夹并打开 Pull Request?
How to commit a folder and open a Pull Request via Github API?
我想通过 Github API.
为用户提交管道配置
到目前为止,我只能将一个名为 main.yaml
的文件提交到存储库的根目录中,但我需要该文件位于 .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
}
]
})
以下代码不正确使用GitHubAPI
// 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) 获取您想要创建新分支的树。请注意,您必须获得 tree sha,而不是 commit sha。
创建一个添加了该文件的新树 (https://docs.github.com/en/rest/reference/git#create-a-tree)。我认为这一步将是最复杂的,因为对于每个创建的 'folder' 树,还需要创建一个父 'folder' 树来包含新创建的 'folder' 树。所以如果你想修改.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
});
有了这个,我删除了很多行代码并解决了我这边的问题,希望对你也有帮助。
我想通过 Github API.
为用户提交管道配置到目前为止,我只能将一个名为 main.yaml
的文件提交到存储库的根目录中,但我需要该文件位于 .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
}
]
})
以下代码不正确使用GitHubAPI
// 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) 获取您想要创建新分支的树。请注意,您必须获得 tree sha,而不是 commit sha。
创建一个添加了该文件的新树 (https://docs.github.com/en/rest/reference/git#create-a-tree)。我认为这一步将是最复杂的,因为对于每个创建的 'folder' 树,还需要创建一个父 'folder' 树来包含新创建的 'folder' 树。所以如果你想修改
.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
});
有了这个,我删除了很多行代码并解决了我这边的问题,希望对你也有帮助。