1 | Git-REST API Wrapper [![NPM](https://img.shields.io/npm/v/git-rest-wrapper?color=red&logo=npm)](https://www.npmjs.com/package/git-rest-wrapper) [![JitPack](https://jitpack.io/v/dev.horrific.code.james/git-rest-wrapper.svg)](https://jitpack.io/#dev.horrific.code.james/git-rest-wrapper) [![Discord](https://img.shields.io/discord/514625116706177035.svg?logo=discord&colorB=7289da)](https://discord.jfenn.me/)
|
2 | =====
|
3 |
|
4 | This is a cross-platform API wrapper for GitHub, GitLab, and Gitea, in an attempt to normalize their API endpoints and promote interoperability. It is being written in [Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) with [ktor](https://ktor.io/), and aims to target the JVM, Android, JS, and native platforms - in other words, (almost) everything that ktor supports.
|
5 |
|
6 | ## Installation
|
7 |
|
8 | ### JavaScript
|
9 |
|
10 | JavaScript projects can use the library through either the [NPM package](https://www.npmjs.com/package/git-rest-wrapper) or by using a compiled bundle hosted on the [UNPKG CDN](https://unpkg.com/browse/git-rest-wrapper/bundle/).
|
11 |
|
12 | #### NPM Module
|
13 |
|
14 | ```shell script
|
15 | npm install git-rest-wrapper
|
16 | ```
|
17 |
|
18 | #### Bundled JS
|
19 |
|
20 | ```html
|
21 | <script type="text/javascript" src="https://unpkg.com/git-rest-wrapper/bundle/gitrest.js"></script>
|
22 | ```
|
23 |
|
24 | ### Gradle / Java
|
25 |
|
26 | The `:gitrest` module is published on [JitPack](https://jitpack.io/), which you can add to your project by copying the following to your root build.gradle at the end of "repositories".
|
27 |
|
28 | ```groovy
|
29 | allprojects {
|
30 | repositories {
|
31 | ...
|
32 | maven { url 'https://jitpack.io' }
|
33 | }
|
34 | }
|
35 | ```
|
36 |
|
37 | To add the dependency to a module, copy this line into your app's build.gradle file.
|
38 |
|
39 | ```groovy
|
40 | implementation "dev.horrific.code.james.git-rest-wrapper:gitrest-jvm:$gitrest_version"
|
41 | ```
|
42 |
|
43 | The Android dependency can be imported similarly, using the root `gitrest` dependency instead of `gitrest-jvm`; gradle should identify & download the `gitrest-android` variant automatically.
|
44 |
|
45 | ```groovy
|
46 | implementation "dev.horrific.code.james.git-rest-wrapper:gitrest:$gitrest_version"
|
47 | ```
|
48 |
|
49 | #### Note: fixing duplicate META-INF files
|
50 |
|
51 | Kotlin Multiplatform has a weird issue with dependency management that I haven't quite worked out; (#5)[https://code.horrific.dev/james/git-rest-wrapper/issues/5] documents some of my encounters with it. Hopefully you won't encounter this problem at all, but if you do, it should be enough to just add the following to your Android modules:
|
52 |
|
53 | ```groovy
|
54 | android {
|
55 | ...
|
56 | packagingOptions {
|
57 | merge 'META-INF/*.kotlin_module'
|
58 | }
|
59 | }
|
60 | ```
|
61 |
|
62 | For any similar errors, adding a line to either `merge` or `exclude 'META-INF/<file>'` should do the trick.
|
63 |
|
64 | ## Usage
|
65 |
|
66 | ### JavaScript
|
67 |
|
68 | After installing the module through NPM, the API wrapper can be used as detailed in the code snippet below.
|
69 |
|
70 | ```js
|
71 | const gitrest = require('git-rest-wrapper');
|
72 | const provider = new gitrest.RequestProvider();
|
73 |
|
74 | provider.getUser("fennifith").then((user) => console.log(user.name));
|
75 | ```
|
76 |
|
77 | The bundled JS file works the same as the NPM module - except the `gitrest` object will be available in the global scope.
|
78 |
|
79 | ```js
|
80 | const provider = new gitrest.RequestProvider();
|
81 |
|
82 | provider.getUser("fennifith").then((user) => console.log(user.name));
|
83 | ```
|
84 |
|
85 | ### Kotlin
|
86 |
|
87 | In Kotlin, you'll need to import `me.jfenn.gitrest.gitrest` and instantiate it as follows (adding or removing providers as you see fit).
|
88 |
|
89 | ```kotlin
|
90 | val client = gitrest {
|
91 | providers = arrayOf(GithubProvider, GitlabProvider, GiteaProvider)
|
92 | cache = MemoryCache()
|
93 | }
|
94 | ```
|
95 |
|
96 | You can optionally add API keys per-domain to any of these providers by using the `tokens` Map as follows:
|
97 |
|
98 | ```kotlin
|
99 | GiteaProvider.apply {
|
100 | tokens["code.horrific.dev"] = "abcxyz"
|
101 | }
|
102 | ```
|
103 |
|
104 | Endpoints can then be accessed using [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)...
|
105 |
|
106 | ```kotlin
|
107 | GlobalScope.launch {
|
108 | val repo = client.getRepo("gitea@code.horrific.dev:james/git-rest-wrapper")
|
109 | println(repo?.description)
|
110 | }
|
111 | ```
|
112 |
|
113 | ### Example Projects
|
114 |
|
115 | - [Kotlin/JS - Browser](./example-kotlinbrowser)
|
116 | - [NodeJS](./example-nodejs)
|
117 | - [JS (Bundle) - Browser](./example-js)
|
118 | - [JVM](./example-jvm)
|
119 | - [Android](./example-android)
|
120 |
|
121 | ## Development
|
122 |
|
123 | The project uses Gradle builds for... err... most things. `./gradlew :{module}:test` and `./gradle :{module}:run` are fairly universal.
|
124 |
|
125 | The `:gitrest:jsBrowserTest` task seems to fail sporadically trying to parse... `/etc/fonts/fonts.conf`? Well, it spits out a lot of logs about it, then fails to actually run any of its tests, so it's not doing very much. It's excluded by default from most gradle tasks.
|
126 |
|
127 | ### Specification
|
128 |
|
129 | #### URI Scheme
|
130 |
|
131 | The library relies on its own identifier format similar to the URI syntax used in SSH - each identifier should be structured as `provider@hostname:id`.
|
132 |
|
133 | - `provider` represents the implementation that should be used for the endpoint, e.g. `gitlab` or `gitea`. If omitted, the wrapper will query various endpoints in an attempt to determine the correct implementation before making the request.
|
134 | - `hostname` represents the host/domain of the server that should be queried. If omitted, the implementation is left to the provider - `github:fennifith/Attribouter` will default to `github.com`, for example.
|
135 | - `id` represents the resource identifier of the item being fetched, specific to the endpoint used.
|
136 |
|
137 | The `provider` and `hostname` values are optional when they can be supplemented by the values in the [`DEFAULT_PROVIDERS`](https://code.horrific.dev/james/git-rest-wrapper/src/branch/main/gitrest/src/commonMain/kotlin/me/jfenn/gitrest/util/DefaultProviders.kt) array. This is also used to "correct" hostnames in cases where the API is served from a different domain than the one provided - for example, `github@github.com:some/repo` will resolve to `github@api.github.com:some/repo`. For compatibility reasons, `github@anything.can.go.here.github.com:some/repo` will exhibit the same behavior.
|
138 |
|
139 | #### Endpoints
|
140 |
|
141 | - `getUser(login)`: `login` is the username of the requested user.
|
142 | - `getRepo(repo)`: `repo` is the repository "path", i.e. `{user}/{repo}` - `james/git-rest-wrapper`, for example.
|
143 | - `getRepoContributors(repo)`: `repo` is the repository "path", same as `getRepo`
|
144 | - `getLicense(key)`: `key` is a short license identifier - refer to [SPDX](https://spdx.org/licenses/) for a complete list (dependent on the server's implementation)
|
145 |
|
146 | #### Models
|
147 |
|
148 | Not all data is complete for every provider/context. For example, Gitea doesn't provide any license information in their Repository model - so that data will obviously be missing.
|
149 |
|
150 | Each data model contains `id`, `context`, and `provider` values with respect to the corresponding portions of the URI.
|
151 |
|
152 | - `User`
|
153 | - `id`: The username.
|
154 | - `name`: The full name of the user (defaults to `login` if unspecified).
|
155 | - `url`: The webpage / user-facing link to the user's profile.
|
156 | - `avatarUrl`: A link to the user's avatar / profile picture.
|
157 | - `websiteUrl`: The user's website / blog / external profile link.
|
158 | - `email`: The user's public email address.
|
159 | - `bio`: The user bio.
|
160 | - `Repo`
|
161 | - `id`: The repository slug identifier, i.e. `james/git-rest-wrapper`
|
162 | - `description`: The repository/project description.
|
163 | - `url`: The webpage / user-facing repository link.
|
164 | - `websiteUrl`: The project website or homepage.
|
165 | - `gitUrlHttp`: HTTP url for `git clone`
|
166 | - `gitUrlSsh`: SSH uri for `git clone`
|
167 | - `license`: Repository `License` object - may be incomplete/missing, depending on implementation.
|
168 | - `defaultBranch`: The default branch of the repository.
|
169 | - `getRawFileUrl(branchName, filePath)`: endpoint used to access a raw file in the repository
|
170 | - `License`
|
171 | - `id`: The license identifier/key, according to SPDX
|
172 | - `name`: A full user-facing license name (defaults to `key` if unspecified)
|
173 | - `description`: A short summary / description of the license.
|
174 | - `body`: The full license text.
|
175 | - `infoUrl`: A user-facing link to license info (ex: [choosealicense.com/licenses/mpl-2.0](https://choosealicense.com/licenses/mpl-2.0/))
|
176 | - `permissions`: An array of license "permissions", ex. `["commercial-use", "distribution", "modification"]`
|
177 | - `conditions`: An array of license "conditions", ex. `["disclose-source", "same-license"]`
|
178 | - `limitations`: An array of license "limitations", ex. `["liability", "warranty"]`
|