Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pushing a tree #1308

Closed
opyate opened this issue Apr 6, 2019 · 9 comments
Closed

Pushing a tree #1308

opyate opened this issue Apr 6, 2019 · 9 comments
Labels
Type: Support Any questions, information, or general needs around the SDK or GitHub APIs

Comments

@opyate
Copy link

opyate commented Apr 6, 2019

I tried these steps: https://github.com/octokit/rest.js/issues/509#issuecomment-370764629

Using version 16.23.2.

Here's my code (borrowed somewhat from here):

import * as Octokit from '@octokit/rest'

let _octokit = null

const octokit = (): Octokit => {
  if (_octokit === null) {
    _octokit = new Octokit({
      auth: '<redacted>'
    })
  }
  return _octokit
}

async function push ({ owner, repo, base, head, changes }) {
  let response

  if (!base) {
    response = await octokit().repos.get({ owner, repo })
    // tslint:disable-next-line:no-parameter-reassignment
    base = response.data.default_branch
  }

  response = await octokit().repos.listCommits({
    owner,
    repo,
    sha: base,
    per_page: 1
  })
  let latestCommitSha = response.data[0].sha
  const treeSha = response.data[0].commit.tree.sha

  response = await octokit().git.createTree({
    owner,
    repo,
    base_tree: treeSha,
    tree: Object.keys(changes.files).map(path => {
      // shut up the compiler...
      const mode: "100644" | "100755" | "040000" | "160000" | "120000" = "100644"
      return {
        path,
        mode,
        content: changes.files[path]
      }
    })
  })
  const newTreeSha = response.data.sha

  response = await octokit().git.createCommit({
    owner,
    repo,
    message: changes.commit,
    tree: newTreeSha,
    parents: [latestCommitSha]
  })
  latestCommitSha = response.data.sha

  // HttpError: Reference does not exist
  return await octokit().git.updateRef({
    owner,
    repo,
    sha: latestCommitSha,
    ref: `refs/heads/${head}`,
    force: true
  })

  // HttpError: Reference already exists
  // return await octokit().git.createRef({
  //   owner,
  //   repo,
  //   sha: latestCommitSha,
  //   ref: `refs/heads/${head}`
  // })
}

const main = async () => {
  const owner = 'opyate'
  const repo = 'deleteme2'
  const base = 'master'
  const head = 'master'
  const changes = {
    files: {
      'README.md': 'Update from octokit' //Buffer.from('Content from octokit.').toString('base64')
    },
    commit: 'Update from octokit'
  }
  return await push({ owner, repo, base, head, changes })
}

main().then(result => {
  console.log(result)
}).catch(err => {
  console.error(err)
})

I'm sure it's a simple fix, but whether I'm creating or updating the ref, I'm getting an error.

Thanks!

@gr2m
Copy link
Contributor

gr2m commented Apr 6, 2019

What is the value of head? Is the repository you are trying it on public? Does the branch you set in head exist before you run the script?

@gr2m gr2m added the Type: Support Any questions, information, or general needs around the SDK or GitHub APIs label Apr 6, 2019
@gr2m
Copy link
Contributor

gr2m commented Apr 6, 2019

It should be as simple as the code here:
https://github.com/gr2m/octokit-create-pull-request/blob/master/lib/create-pull-request.js

without the last step creating the pull request

@opyate
Copy link
Author

opyate commented Apr 6, 2019

What is the value of head?

From my example above:

const owner = 'opyate'
  const repo = 'deleteme2'
  const base = 'master'
  const head = 'master'

Is the repository you are trying it on public?

Yes.

Does the branch you set in head exist before you run the script?

master exists, yes.

It should be as simple as the code here: https://github.com/gr2m/octokit-create-pull-request/blob/master/lib/create-pull-request.js without the last step creating the pull request

That was exactly my thoughts. Where I say "Here's my code (borrowed somewhat from here):" I'm actually pointing to that exact same repo.

@gr2m
Copy link
Contributor

gr2m commented Apr 6, 2019

Can you try

  return await octokit().git.updateRef({
    owner,
    repo,
    sha: latestCommitSha,
-   ref: `refs/heads/${head}`,
+   ref: `heads/${head}`,
    force: true
  })

@opyate
Copy link
Author

opyate commented Apr 6, 2019

https://octokit.github.io/rest.js/#api-Git-createRef says about ref:

If it doesn't start with 'refs' and have at least two slashes, it will be rejected.

...but weirdly, your suggestion worked. Thanks!

Are the docs wrong?

@opyate
Copy link
Author

opyate commented Apr 6, 2019

Actually, I'm using https://octokit.github.io/rest.js/#api-Git-updateRef which does not have a doc for ref.

@opyate opyate closed this as completed Apr 6, 2019
@gr2m
Copy link
Contributor

gr2m commented Apr 6, 2019

yeah, it’s a known API weirdness :/ many folks run into this, including myself. I’m considering to normalize the ref parameters across the Octokit methods

@opyate
Copy link
Author

opyate commented Apr 6, 2019

Well, thanks again. I do appreciate you taking time out on a Saturday to look at this.

@opyate
Copy link
Author

opyate commented Apr 7, 2019

Not sure if I should open a new issue for this question or whether it's a good idea to beef up this issue with extra info, but I'm now wondering how to push a tree containing images, or non-text content type. It seems as if content negotiation isn't happening automatically on file extension, and the docs at https://octokit.github.io/rest.js/#api-Git-createTree don't show any obvious option to do this either.

Here's the last bit of the example above modified:

import * as fs from 'fs'

function getImageAsBase64(file) {
  const bitmap = fs.readFileSync(file)
  return new Buffer(bitmap).toString('base64')
}

const main = async () => {
  const owner = 'opyate'
  const repo = 'deleteme2'
  const base = 'master'
  const head = 'master'
  const changes = {
    files: {
      'foo.png': getImageAsBase64('/path/to/image.png')
    },
    commit: 'Image from octokit'
  }
  return await push({ owner, repo, base, head, changes })
}

And the resulting image is just the base64 string:
https://github.com/opyate/deleteme2/blob/master/foo.png

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Support Any questions, information, or general needs around the SDK or GitHub APIs
Projects
None yet
Development

No branches or pull requests

2 participants