Created
October 12, 2018 15:28
-
-
Save wsalesky/4f24c7619f52588435fbbba9ac2b3741 to your computer and use it in GitHub Desktop.
XQuery to commit content to GitHub. Query creates a new branch, commits content and creates a new pull request to specified repository.
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.1"; | |
(:~ | |
: POC: XQuery to commit content to github reop via github API. Tested in eXist-db v4.4.0 | |
: Code creates a new branch off of the master branch, commits updated content to the new branch | |
: and then submits a pull request when complete. Intended use is for online data submission, | |
: using GitHub for review/approval process. | |
: | |
: 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 the github repository you would like to commit to. | |
: @see https://github.com/blog/1509-personal-api-tokens | |
: | |
: Github API Steps for creating/updating repository contents: | |
: 1. Get a reference to HEAD of branch, in this case we use the master branch | |
: Save sha and url from github response | |
: 2. Create a new branch for your changes | |
: Save sha and url from GitHub response on the new branch | |
: 3. Get the latest commit for the new branch | |
: Save sha, tree sha and tree url | |
: 4. Post your content to GitHub | |
: Save sha | |
: 5. Create a tree containing your new content | |
: Save sha | |
: 6. Create a new commit | |
: Save commit sha | |
: 7. Update refs (of the created branch) with new commit information | |
: 8. Create a pull request | |
: If step 7 returns @status='200' create a pull request. | |
: | |
: 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/ (*This was the most helpful) | |
: http://patrick-mckinley.com/tech/github-api-commit.html | |
: | |
: @author Winona Salesky | |
: @version 1.0 | |
:) | |
import module namespace http="http://expath.org/ns/http-client"; | |
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization"; | |
declare namespace json = "http://www.json.org"; | |
(: Path for your file on github :) | |
declare variable $path {request:get-parameter('path', 'data/places/tei/1.xml')}; | |
(: A commit message :) | |
declare variable $commit-message {request:get-parameter('commit', 'Update GitHub repository from online form submission')}; | |
(: Create a branch name, uses filepath and exist-db uril:random() to branch name. :) | |
let $branch-name := concat(replace($path,'/|\.',''),'-',replace(util:random(),'\.','')) | |
(: Full path to GitHub Repository:) | |
let $repo := 'https://api.github.com/repos/wsalesky/blogs' | |
(: Authorization token from GitHub:) | |
let $authorization-token := 'YOUR-ACCESS-TOKEN_HERE' | |
(: Content. Generate as you wish. :) | |
let $new-content := | |
'<TEI xmlns="http://www.tei-c.org/ns/1.0" xml:lang="en"> | |
<teiHeader> | |
<fileDesc> | |
<titleStmt> | |
<title level="a" xml:lang="es">San Nicolas de Tumbez</title> | |
<title level="m" xml:lang="en">New title</title> | |
<title level="m" xml:lang="en">New title2</title> | |
</titleStmt> | |
</fileDesc> | |
</teiHeader> | |
</TEI> | |
' | |
(: 1. Get a reference to HEAD of branch, master:) | |
let $branch := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/refs/heads/master'))}" method="get"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
</http:request>)[2]) | |
(: Get latest commit SHA from master branch :) | |
let $branch-sha := parse-json($branch)?object?sha | |
(: Get latest commit SHA from master branch :) | |
let $branch-url := parse-json($branch)?object?url | |
(: 2. create a new branch :) | |
let $new-branch-name := | |
serialize( | |
<object> | |
<ref>refs/heads/{$branch-name}</ref> | |
<sha>{$branch-sha}</sha> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters>) | |
let $new-branch := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/refs'))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$new-branch-name}</http:body> | |
</http:request>)[2]) | |
(: Get latest commit SHA from master branch :) | |
let $new-branch-sha := parse-json($new-branch)?object?sha | |
(: Get latest commit SHA from master branch :) | |
let $new-branch-url := parse-json($new-branch)?object?url | |
(: 3. Get the latest commit for the new branch :) | |
let $get-latest-commit := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI($new-branch-url)}" method="get"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
</http:request>)[2]) | |
(:Note the commit SHA, the tree SHA, and the tree URL.:) | |
let $get-latest-commit-sha := parse-json($get-latest-commit)?sha | |
let $get-latest-commit-tree-sha := parse-json($get-latest-commit)?tree?sha | |
let $get-latest-commit-tree-url := parse-json($get-latest-commit)?tree?url | |
(: 4. Post your content to github :) | |
(: Create new blob with new content base64/utf-8 :) | |
let $new-blob-content := | |
serialize( | |
<object> | |
<content>{$new-content}</content> | |
<encoding>utf-8</encoding> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters>) | |
let $new-blob := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/blobs'))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$new-blob-content}</http:body> | |
</http:request>)[2]) | |
let $blob-sha := parse-json($new-blob)?sha | |
(: 4. Get a hold of the tree that the commit points to :) | |
let $get-tree := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI($get-latest-commit-tree-url)}" method="get"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
</http:request>)[2]) | |
let $get-tree-sha := parse-json($get-latest-commit)?sha | |
(: 5. Create a tree containing your new content :) | |
let $new-tree-content := | |
serialize( | |
<object> | |
<base_tree>{$get-tree-sha}</base_tree> | |
<tree json:array="true"> | |
<path>{$path}</path> | |
<mode>100644</mode> | |
<type>blob</type> | |
<sha>{$blob-sha}</sha> | |
</tree> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters> | |
) | |
let $new-tree := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/trees'))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$new-tree-content}</http:body> | |
</http:request>)[2]) | |
let $get-new-tree-sha := parse-json($new-tree)?sha | |
(: 6. Create a new commit :) | |
(: Update refs in repository to your new commit SHA :) | |
let $commit-ref-data := | |
serialize( | |
<object> | |
<message>{$commit-message}</message> | |
<parents json:array="true">{$get-latest-commit-sha}</parents> | |
<tree>{$get-new-tree-sha}</tree> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters> | |
) | |
let $commit := | |
util:base64-decode( | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/commits'))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$commit-ref-data}</http:body> | |
</http:request>)[2]) | |
let $commit-sha := parse-json($commit)?sha | |
(: 7. Update refs :) | |
let $update-ref := | |
serialize( | |
<object> | |
<sha>{$commit-sha}</sha> | |
<force json:literal="true">true</force> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters> | |
) | |
let $commit-ref := | |
http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/git/refs/heads/',$branch-name))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$update-ref}</http:body> | |
</http:request>)[1] | |
(: 8. Create a pull request :) | |
return | |
if(string($commit-ref/@status) = '200') then | |
let $pull-request-data := | |
serialize( | |
<object> | |
<title>Updates from online corrections. {$path}</title> | |
<body>Review submitted changes and merge into master if acceptable.</body> | |
<head>{$branch-name}</head> | |
<base>master</base> | |
</object>, | |
<output:serialization-parameters> | |
<output:method>json</output:method> | |
</output:serialization-parameters> | |
) | |
let $pull-request := | |
util:base64-decode(http:send-request(<http:request http-version="1.1" href="{xs:anyURI(concat($repo,'/pulls'))}" method="post"> | |
<http:header name="Authorization" value="{concat('token ',$authorization-token)}"/> | |
<http:header name="Connection" value="close"/> | |
<http:header name="Accept" value="application/json"/> | |
<http:body media-type="application/json" method="text">{$pull-request-data}</http:body> | |
</http:request>)[2]) | |
return $pull-request | |
else $commit-ref |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment