Skip to content

Instantly share code, notes, and snippets.

@wsalesky
Created October 12, 2018 15:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wsalesky/4f24c7619f52588435fbbba9ac2b3741 to your computer and use it in GitHub Desktop.
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.
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