繁体   English   中英

如何通过 Github API 提交文件夹并打开 Pull Request?

[英]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 
    }
  ]
})

以下代码没有正确使用 GitHub API

// 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 在原始树的基础上创建一棵全新的树。

脚步

  1. 为新文件创建 blob ( https://docs.github.com/en/rest/reference/git#create-a-blob )。 您已经很好地完成了这一步。

  2. 获取您想要创建新分支的树( https://docs.github.com/en/rest/reference/repos#get-a-branch )。 请注意,您必须获取树 sha ,而不是提交 sha

  3. 使用添加的文件创建一个新树 ( https://docs.github.com/en/rest/reference/git#create-a-tree )。 我认为这一步将是最复杂的,因为对于每个创建的“文件夹”树,还需要创建一个父“文件夹”树以包含新创建的“文件夹”树。 所以如果你想修改.github/workflows文件夹,你首先必须创建一个基于.github/workflows的新树。 比方说 tree sha 是abc... 然后,您需要基于.github文件夹创建一棵新树,并将workflows目录设为abc... ,而不是旧目录。

  4. 创建一个提交( https://docs.github.com/en/rest/reference/git#create-a-commit )。 使用您在上一步中创建的根树的 sha。

  5. 创建一个新分支 ( https://docs.github.com/en/rest/reference/git#create-a-reference )。 在问题代码中,您在创建提交之前创建了它,这是没有意义的。 您需要在创建提交创建它,以便它的头部指向您创建的提交的 sha。

  6. 创建拉取请求 ( 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)
          ...
      ...
  ...

视觉对象中有三个--> 每个-->都是一个请求。

  1. 从创建^c树开始,它基于c树并添加了main.yml文件。
  2. 创建^b树,它基于b但其中包含^c
  3. 创建^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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM