10

I need help with GitHub API,

I need commit new version of file through API, I'm trying to achieve this by sending post request to

https://api.github.com/repos/:username/:repo:/git/commits/

with data

{
    "login": "username",
    "token": "auth_token",
    "parent_commit": "sha",
    "message": "commit message.",
    "content": {
        "path": "full/path",
        "mode": "edit",
        "data": "new content"
    }
}

But it fails with result - not found.

Have anyone idea where to send this request and if this format is right?

(Format is inspired by - http://swanson.github.com/blog/2011/07/23/digging-around-the-github-api-take-2.html)

3 Answers 3

9

Committing new content is actually a multi-step process, using their low level and powerful API

Actually, since Sept. 2021 (9 years later), it is not, but using the GraphQL GitHub API v4 (instead of the GitHub API v3)

See:

A simpler API for authoring commits:

The new GraphQL mutation createCommitOnBranch makes it easier to add, update, and delete files in a branch of a repository.

This new API offers a simpler way to commit changes compared to the existing Git database REST APIs.
With the new createCommitOnBranch mutation, you do not need to manually create blobs and trees before creating the commit. This allows you to add, update, or delete multiple files in a single API call.

Commits authored using the new API are automatically GPG signed and are marked as verified in the GitHub UI. GitHub Apps can use the mutation to author commits directly or on behalf of users.

$ curl https://api.github.com/graphql \ 
       -s -H "Authorization: bearer $TOKEN"
       --data @- <<GRAPHQL | jq \
         '.data.createCommitOnBranch.commit.url[0:56]'
{
  "query": "mutation (\$input: CreateCommitOnBranchInput!) {
    createCommitOnBranch(input: \$input) { commit { url } } }",

  "variables": {
    "input": {
      "branch": {
        "repositoryNameWithOwner": "demo-githubs/test",
        "branchName": "main"
      },
      "message": {"headline": "Hello from GraphQL!" },
      "fileChanges": {
        "additions": [{
            "path": "GraphQL.md",
            "contents": "`echo 'Hello, GraphQL! | base64`"
        }],
        "deletions": [{ "path": "REST.txt" }]
      },
      "expectedHeadOid": "git rev-parse HEAD"
}}}
GRAPHQL

graphql


Can I set up a committer using the api?

Yes, you should be able to set up a bot as a committer in GitHub actions, but not using the API.

As noted by 沙漠之子 in the comments:

Currently, API v4's CreateCommitOnBranch explicitly does not support setting the committer.
API v3 creates commits with signatures, and must set the private key.
See "Creating a signed commit via API".

Without API:

When you utilize a GitHub action to commit files, the default committer is the GitHub Actions bot. However, you can customize the committer by setting the git user and email before making the commit.

In your GitHub action workflow file (e.g., .github/workflows/main.yml), you can configure the git user and email before making the commit.

name: Committer Action

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Configure git
      run: |
        git config user.name "Your Bot Name"
        git config user.email "[email protected]"

    - name: Make a commit
      run: |
        echo "New Content" > file.txt
        git add file.txt
        git commit -m "Commit by bot"
        git push

That way, the bot will be recognized as the committer for any changes pushed through this action.

Sign up to request clarification or add additional context in comments.

8 Comments

Facing this for a first commit ---> "Argument 'expectedHeadOid' on InputObject 'CreateCommitOnBranchInput' has an invalid value (\"git rev-parse HEAD\"). Expected type 'GitObjectID!'."
@ranit Yes, probably because your first commit does not have parent. Can you confirm this works for a commit on top of existing commits?
Banging my head at this one as well. How can one get the value for expectedHeadOid using the Graphql API? (See question: stackoverflow.com/questions/72836597/…)
Can I set up a committer? It seems that no relevant information was found. I want to use bot as committer in GitHub action.
@沙漠之子 I have edited the answer to address your comment.
|
8

Note that since May 2013, you have a CRUD API available:

That includes a file update API

{
  "message": "my commit message",
  "committer": {
    "name": "Scott Chacon",
    "email": "[email protected]"
  },
  "content": "bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz",
  "sha": "329688480d39049927147c162b9d2deaf885005f"
}

(with content being the updated file content, Base64 encoded.)

Comments

5

I puzzled over this one too!

Committing new content is actually a multi-step process, using their low level and powerful API.

Here is a gist I made to share one solution. Note that a few things are hard coded, like the branch name "master". It commits and pushes via the Github REST API, using the Ruby RestClient.

Please feel free to fork and improve the gist, or let me know if you're having trouble getting this to run.

Here's the code of the gist, push_to_githuh.rb:

# Committing changes to a repo via the Github API is not entirely trivial.
# The five-step process is outlined here:
#   http://developer.github.com/v3/git/
#
# Matt Swanson wrote a blog post translating the above steps into actual API calls:
#   http://swanson.github.com/blog/2011/07/23/digging-around-the-github-api-take-2.html
# 
# I was not able to find sample code for actually doing this in Ruby, 
# either via the HTTP API or any of the gems that wrap the API.
# So in the hopes it will help others, here is a simple function to 
# commit a single file to github via the API.  The code only handles 
# the case of committing a single file to the master branch,
# but should be easy to modify for your own needs.
# 
# Note also that we use HTTP basic auth, not OAuth, in this example.
#
# Prerequisites:
#
#   $ gem install rest-client
#   $ export GH_USERNAME=xxxx
#   $ export GH_PASSWORD=yyyy
#
# Usage:
#
#   push_to_github :path => "path/to/file.txt", :content => "hello commit", :repo => 'test'
#
# In the above example, the repo 'test' must be owned by GH_USERNAME, and have at least one commit.
#
# No news is good news.  If you don't raise exceptions, you should see the commit in your repo.
#
# CC0 Public Domain Dedication
# To the extent possible under law, Harlan T Wood
# has waived all copyright and related or neighboring
# rights to this work.
# http://creativecommons.org/publicdomain/zero/1.0/
#

require 'rest_client'
require 'json'

def push_to_github(params)
  repo = params[:repo]

  # get the head of the master branch
  # see http://developer.github.com/v3/git/refs/
  branch = github(:get, repo, "refs/heads/master")
  last_commit_sha = branch['object']['sha']

  # get the last commit
  # see http://developer.github.com/v3/git/commits/
  last_commit = github :get, repo, "commits/#{last_commit_sha}"
  last_tree_sha = last_commit['tree']['sha']

  # create tree object (also implicitly creates a blob based on content)
  # see http://developer.github.com/v3/git/trees/
  new_content_tree = github :post, repo, :trees,
                            :base_tree => last_tree_sha,
                            :tree => [{:path => params[:path], :content => params[:content], :mode => '100644'}]
  new_content_tree_sha = new_content_tree['sha']

  # create commit
  # see http://developer.github.com/v3/git/commits/
  new_commit = github :post, repo, :commits,
                      :parents => [last_commit_sha],
                      :tree => new_content_tree_sha,
                      :message => 'commit via api'
  new_commit_sha = new_commit['sha']

  # update branch to point to new commit
  # see http://developer.github.com/v3/git/refs/
  github :patch, repo, "refs/heads/master",
         :sha => new_commit_sha
end

def github(method, repo, resource, params={})
  resource_url = "https://#{ENV['GITHUB_USER']}:#{ENV['GITHUB_PASS']}@api.github.com" +
    "/repos/#{ENV['GITHUB_USER']}/#{repo}/git/#{resource}"
  if params.empty?
    JSON.parse RestClient.send(method, resource_url)
  else
    JSON.parse RestClient.send(method, resource_url, params.to_json, :content_type => :json, :accept => :json)
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.