Last active
September 28, 2015 16:22
-
-
Save wsalesky/5b18bc02af76f889da10 to your computer and use it in GitHub Desktop.
Version of git-commit using expath http client. Still a work in progress.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xquery version "3.0"; | |
(:~ | |
: POC: eXist DB module to commit files to github reop via github API | |
: Prerequisites: | |
: In order to run the module, you will need a github Authorization token. | |
: When you create authorization token your OAuth Scope will need to include repo, allowing you to update files. | |
: @see https://github.com/blog/1509-personal-api-tokens | |
: | |
: @Notes | |
: This version EXpath http client. | |
: Additional development will be needed to handle creating new files/directories, deletes and merge conflicts. | |
: @see http://exist.2174344.n4.nabble.com/Problem-converting-Base64Binary-data-to-raw-binary-data-for-Google-Drive-Api-td4665281.html | |
: | |
: Github API Steps for creating/updating repository contents: | |
: 1. get the current commit object | |
: 2. retrieve the tree it points to | |
: 3. retrieve the content of the blob object that tree has for that particular file path | |
: 4. change the content somehow and post a new blob object with that new content, getting a blob SHA back | |
: 5. post a new tree object with that file path pointer replaced with your new blob SHA getting a tree SHA back | |
: 6. create a new commit object with the current commit SHA as the parent and the new tree SHA, getting a commit SHA back | |
: 7. update the reference of your branch to point to the new commit SHA | |
: | |
: Links to useful github api info | |
: https://developer.github.com/v3/ | |
: https://developer.github.com/v3/git/ | |
: https://gist.github.com/jasonrudolph/10727108 | |
: http://www.mdswanson.com/blog/2011/07/23/digging-around-the-github-api-take-2.html | |
: http://www.levibotelho.com/development/commit-a-file-with-the-github-api/ | |
: http://patrick-mckinley.com/tech/github-api-commit.html | |
: | |
: @author Winona Salesky | |
: @version 0.1 | |
: | |
: @see https://github.com/joewiz/xqjson | |
: @see http://exist-db.org/xquery/util | |
: @see http://exist-db.org/xquery/httpclient | |
: | |
:) | |
import module namespace xqjson="http://xqilla.sourceforge.net/lib/xqjson"; | |
import module namespace http="http://expath.org/ns/http-client"; | |
declare namespace httpclient="http://exist-db.org/xquery/httpclient"; | |
(: Pass updated file path and commit message via parameters :) | |
declare variable $path {request:get-parameter('path', 'README.md')}; | |
declare variable $commit {request:get-parameter('commit', 'Update README. testing github API with parameters.')}; | |
(:~ | |
: New content to submit | |
: @param $path path to updated file in eXist (relative to app root) | |
: Should be passed with either, see notes on issue with this method: | |
: util:base64-encode(doc($path)) | |
: util:base64-encode(util:binary-doc($path)) | |
:) | |
declare variable $new-content {'Testing utf-8 text from xquery to github. Still problems with submitting binary files, or using expath http.'}; | |
(: Path to your github repository. eg: https://api.github.com/repos/wsalesky/blogs :) | |
declare variable $repo {'REPOSITORY-URL'}; | |
(: | |
: You will need to have an github authorization token to run this script. | |
: See https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization | |
: Best practice would be to store this token in an environmental variable on | |
: your server and retrieve it via environment-variable() | |
:) | |
declare variable $authorization-token {'YOUR-AUTH-TOKEN'}; | |
(:~ | |
: HTTP Headers for authorization | |
: @param $authorization-token your github authorization token | |
:) | |
declare function local:build-request($url as xs:anyURI?, $method as xs:string?, $content as item()*){ | |
http:send-request( | |
<http:request href="{$url}" method="{$method}"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
{if($content) then <http:body media-type="application/json" method="text">{$content}</http:body> else ()} | |
</http:request>) | |
}; | |
(: Get master branch of $repo :) | |
let $latest-commit := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/refs/heads/master')),'get',())[2])) | |
let $get-latest-commit-sha := $latest-commit//pair[@name='sha']/text() | |
(: Get latest commit tree using $get-latest-commit-sha :) | |
let $get-latest-commit := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/commits/',$get-latest-commit-sha)),'get',())[2])) | |
(: Get latest commit tree SHA :) | |
let $latest-commit-tree-sha := $get-latest-commit//pair[@name='tree']/pair[@name='sha']/text() | |
(: Get latest tree using $latest-commit-tree-sha :) | |
let $get-latest-tree := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/trees/',$latest-commit-tree-sha)),'get', ())[2])) | |
(: Github documentation suggests getting the file SHA and content, but then never uses it. Currently commented out:) | |
(: Get file SHA from latest tree :) | |
(:let $get-file-sha-from-tree := $get-latest-tree//pair[@name='path'][. = {$path}]/following-sibling::pair[@name='sha'][1]/text():) | |
(: Get file blob from $get-file-sha-from-tree :) | |
(: | |
let $get-blob := xqjson:parse-json(util:base64-decode(httpclient:get(xs:anyURI(concat($repo,'/git/blobs/',$get-file-sha-from-tree)),false(), $headers)[2])) | |
let $blob-sha := $get-blob/pair[@name='sha']/text() | |
:) | |
(: Create new blob with new content base64/utf-8 :) | |
let $new-blob-content := | |
xqjson:serialize-json( | |
<pair name="object" type="object"> | |
<pair name="content" type="string">{util:serialize($new-content, 'method=xml')}</pair> | |
<pair name="encoding" type="string">utf-8</pair> | |
</pair>) | |
(: Send new blob-content to Github API:) | |
let $new-blob := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/blobs')),'post', $new-blob-content)[2])) | |
(: New blob sha :) | |
let $new-blob-sha := $new-blob/pair[@name='sha']/text() | |
(: | |
: Create a new tree | |
: New tree includes | |
: base_tree: $latest-commit-tree-sha (the tree referenced in the latest commit, referenced in the master branch.) | |
: path: path to the new/updated file relative to app/repo root. | |
: sha: $new-blob-sha (SHA for the just created new content blob) | |
:) | |
let $new-tree-content := | |
xqjson:serialize-json( | |
<pair name="object" type="object"> | |
<pair name="base_tree" type="string">{$latest-commit-tree-sha}</pair> | |
<pair name="tree" type="array"> | |
<pair name="object" type="object"> | |
<pair name="path" type="string">{$path}</pair> | |
<pair name="mode" type="string">100644</pair> | |
<pair name="type" type="string">blob</pair> | |
<pair name="sha" type="string">{$new-blob-sha}</pair> | |
</pair> | |
</pair> | |
</pair>) | |
(: Send new tree to Github API:) | |
let $new-tree := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/trees')),'post', $new-tree-content)[2])) | |
(: New tree SHA :) | |
let $new-tree-sha := $new-tree/pair[@name='sha']/text() | |
(: | |
: Create new commit | |
: message: commit message | |
: tree: $new-tree-sha (the SHA of the tree you have just created for your new content) | |
: parents: $get-latest-commit-sha (an array of parent SHA's, can be just one, should not be empty) | |
:) | |
let $new-commit-content := | |
xqjson:serialize-json( | |
<pair name="object" type="object"> | |
<pair name="message" type="string">{$commit}</pair> | |
<pair name="tree" type="string">{$new-tree-sha}</pair> | |
<pair name="parents" type="array"><item type="string">{$get-latest-commit-sha}</item></pair> | |
</pair>) | |
(: Send new commit to Github API:) | |
let $new-commit := xqjson:parse-json(util:base64-decode(local:build-request(xs:anyURI(concat($repo,'/git/commits')), 'post',$new-commit-content)[2])) | |
(: New commit SHA :) | |
let $new-commit-sha := $new-commit/self::json[@type='object']/pair[@name='sha']/text() | |
(: Update refs in repository to your new commit SHA :) | |
let $commit-ref-data := | |
xqjson:serialize-json( | |
<pair name="object" type="object"> | |
<pair name="sha" type="string">{$new-commit-sha}</pair> | |
<pair name="force" type="boolean">true</pair> | |
</pair>) | |
let $commit-ref := local:build-request(xs:anyURI(concat($repo,'/git/refs/heads/master')),'post', $commit-ref-data) | |
let $commit-ref-message := util:base64-decode($commit-ref[2]) | |
return $commit-ref-message |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment