|
1 |
| -# 🚧 WORK IN PROGRESS. See [#1](https://github.com/probot/octokit-plugin-config/pull/1) |
2 |
| - |
3 | 1 | # octokit-plugin-config
|
4 | 2 |
|
5 | 3 | > Get/set persisted configuration using YAML/JSON files in repositories
|
6 | 4 |
|
| 5 | +[](https://www.npmjs.com/package/@probot/octokit-plugin-config) |
| 6 | +[](https://github.com/probot/octokit-plugin-config/actions?query=workflow%3ATest+branch%3Amain) |
| 7 | +[](https://dependabot.com/) |
| 8 | + |
| 9 | +By default, this plugin loads configuration from a given repository file. If the file doesn't exist, it loads configuration from the same path in the same owner's `.github` repository. |
| 10 | + |
| 11 | +Configuration can be extended across multiple files using [the `_extends` key](#extends). |
| 12 | + |
| 13 | +## Usage |
| 14 | + |
| 15 | +<table> |
| 16 | +<tbody valign=top align=left> |
| 17 | +<tr><th> |
| 18 | + |
| 19 | +Browsers |
| 20 | + |
| 21 | +</th><td width=100%> |
| 22 | + |
| 23 | +Load `@probot/octokit-plugin-config` and [`@octokit/core`](https://github.com/octokit/core.js) (or core-compatible module) directly from [cdn.pika.dev](https://cdn.pika.dev) |
| 24 | + |
| 25 | +```html |
| 26 | +<script type="module"> |
| 27 | + import { Octokit } from "https://cdn.pika.dev/@octokit/core"; |
| 28 | + import { |
| 29 | + config, |
| 30 | + composeConfigGet, |
| 31 | + } from "https://cdn.pika.dev/@probot/octokit-plugin-config"; |
| 32 | +</script> |
| 33 | +``` |
| 34 | + |
| 35 | +</td></tr> |
| 36 | +<tr><th> |
| 37 | + |
| 38 | +Node |
| 39 | + |
| 40 | +</th><td> |
| 41 | + |
| 42 | +Install with `npm install @octokit/core @probot/octokit-plugin-config`. Optionally replace `@octokit/core` with a compatible module |
| 43 | + |
| 44 | +```js |
| 45 | +const { Octokit } = require("@octokit/core"); |
| 46 | +const { config, composeConfigGet } = require("@probot/octokit-plugin-config"); |
| 47 | +``` |
| 48 | + |
| 49 | +</td></tr> |
| 50 | +</tbody> |
| 51 | +</table> |
| 52 | + |
| 53 | +```js |
| 54 | +// given that `.github/my-app.yml` in `octocat/hello-world` has the following ocntent |
| 55 | +// |
| 56 | +// comment: 'Thank you for creating the issue!' |
| 57 | +// |
| 58 | +const { config } = await octokit.config.get({ |
| 59 | + owner: "octocat", |
| 60 | + repo: "hello-world", |
| 61 | + path: ".github/my-app.yml", |
| 62 | +}); |
| 63 | +// config is now { comment: "Thank you for creating the issue!" } |
| 64 | + |
| 65 | +// all options and returns |
| 66 | +const { config, files } = await octokit.config.get({ |
| 67 | + owner: "octocat", |
| 68 | + repo: "hello-world", |
| 69 | + path: ".github/my-app.yml", |
| 70 | + defaults: { |
| 71 | + comment: "Thank you for creating the issue!", |
| 72 | + }, |
| 73 | + branch: "develop", |
| 74 | +}); |
| 75 | +// files is an array of { owner, repo, path, config } objects |
| 76 | +``` |
| 77 | + |
| 78 | +## Options |
| 79 | + |
| 80 | +<table> |
| 81 | + <thead align=left> |
| 82 | + <tr> |
| 83 | + <th> |
| 84 | + option |
| 85 | + </th> |
| 86 | + <th> |
| 87 | + type |
| 88 | + </th> |
| 89 | + <th width=100%> |
| 90 | + description |
| 91 | + </th> |
| 92 | + </tr> |
| 93 | + </thead> |
| 94 | + <tbody align=left valign=top> |
| 95 | + <tr> |
| 96 | + <th><code>owner</code></th> |
| 97 | + <td>String</td> |
| 98 | + <td> |
| 99 | + <strong>Required.</strong> Repository owner login. |
| 100 | + </td> |
| 101 | + </tr> |
| 102 | + <tr> |
| 103 | + <th><code>repo</code></th> |
| 104 | + <td>String</td> |
| 105 | + <td> |
| 106 | + <strong>Required.</strong> Repository name. |
| 107 | + </td> |
| 108 | + </tr> |
| 109 | + <tr> |
| 110 | + <th><code>path</code></th> |
| 111 | + <td>String</td> |
| 112 | + <td> |
| 113 | + <strong>Required.</strong> Path of the configuration file. Supported file extensions are <code>.yml</code>, <code>.yaml</code>, and <code>.json</code>. |
| 114 | + </td> |
| 115 | + </tr> |
| 116 | + <tr> |
| 117 | + <th><code>defaults</code></th> |
| 118 | + <td>String</td> |
| 119 | + <td> |
| 120 | + Default options that are returned if the configuration file does not exist, or merged with the contents if it does exist. Defaults are merged using shallowly using <code>Object.assign</code>. For custom merge strategies, you can set <code>defaults</code> to a function, see <a href="#custom-configuration-merging">Merging configuration</a> below for more information. Defaults to <code>{}</code>. |
| 121 | + </td> |
| 122 | + </tr> |
| 123 | + <tr> |
| 124 | + <th><code>branch</code></th> |
| 125 | + <td>String</td> |
| 126 | + <td> |
| 127 | + Defaults to the repository's default branch. The branch is only used for the provided repository, not for the <code>.github<code> repository or other configurations linked using <a href="extends">the <code>_extends</code> key</a>. |
| 128 | + </td> |
| 129 | + </tr> |
| 130 | + </tbody> |
| 131 | +</table> |
| 132 | + |
| 133 | +<a name="extends"></a> |
| 134 | + |
| 135 | +### The `_extends` key |
| 136 | + |
| 137 | +`octokit.config.get()` supports sharing configs between repositories. If configuration for your app is not available in the target repository, it will be loaded from the `.github` directory of the same owner's `.github` repository. |
| 138 | + |
| 139 | +You can choose own shared location. Use the `_extends` option in the configuration file to extend settings from another repository. |
| 140 | + |
| 141 | +For example, given `.github/test.yml`: |
| 142 | + |
| 143 | +```yml |
| 144 | +_extends: github-settings |
| 145 | +# Override values from the extended config or define new values |
| 146 | +name: myrepo |
| 147 | +``` |
| 148 | +
|
| 149 | +This configuration will be merged with the `.github/test.yml` file from the `github-settings` repository, which might look like this: |
| 150 | + |
| 151 | +```yml |
| 152 | +shared1: will be merged |
| 153 | +shared2: will also be merged |
| 154 | +``` |
| 155 | + |
| 156 | +Just put common configuration keys in a repository within your organization. Then reference this repository from config files with the same name. |
| 157 | + |
| 158 | +You can also reference configurations from other owners: |
| 159 | + |
| 160 | +```yml |
| 161 | +_extends: other/probot-settings |
| 162 | +other: DDD |
| 163 | +``` |
| 164 | + |
| 165 | +Additionally, you can specify a specific path for the configuration by appending a colon after the project. |
| 166 | + |
| 167 | +```yml |
| 168 | +_extends: probot-settings:.github/other_test.yml |
| 169 | +other: FFF |
| 170 | +``` |
| 171 | + |
| 172 | +<a name="custom-configuration-merging"></a> |
| 173 | + |
| 174 | +### Merging configuration |
| 175 | + |
| 176 | +Given `.github/test.yml`: |
| 177 | + |
| 178 | +```yml |
| 179 | +settings: |
| 180 | + one: value from configuration |
| 181 | +``` |
| 182 | + |
| 183 | +And |
| 184 | + |
| 185 | +```js |
| 186 | +const { config } = await octokit.config.get({ |
| 187 | + owner, |
| 188 | + repo, |
| 189 | + path: ".github/test.yml", |
| 190 | + defaults: { |
| 191 | + settings: { |
| 192 | + one: "default value", |
| 193 | + two: "default value", |
| 194 | + }, |
| 195 | + }, |
| 196 | +}); |
| 197 | +``` |
| 198 | + |
| 199 | +The resulting `config` object is |
| 200 | + |
| 201 | +```js |
| 202 | +{ |
| 203 | + settings: { |
| 204 | + one: "value from configuration"; |
| 205 | + } |
| 206 | +} |
| 207 | +``` |
| 208 | + |
| 209 | +And not as you might expect |
| 210 | + |
| 211 | +```js |
| 212 | +{ |
| 213 | + settings: { |
| 214 | + one: "value from configuration"; |
| 215 | + two: "default value"; |
| 216 | + } |
| 217 | +} |
| 218 | +``` |
| 219 | + |
| 220 | +The reason for that behavior is that merging objects deeply is not supported in JavaScript by default, and there are different strategies and many pitfals. There are many libraries that support deep merging in different ways, but instead making that decision for and significantly increasing the bundle size of this plugin, we let you pass a custom merge strategy instead. |
| 221 | + |
| 222 | +In order to achive the deeply merged configuration, the `defaults` option can be set to a function. The function receives one `configs` argument, which is an array of configurations loaded from files in reverse order, so that the latter items should take precedence over the former items. The `configs` array can have more than one object if [the `_extends` key](#extends) is used. |
| 223 | + |
| 224 | +```js |
| 225 | +const defaults = { |
| 226 | + settings: { |
| 227 | + one: "default value", |
| 228 | + two: "default value", |
| 229 | + }, |
| 230 | +}; |
| 231 | +const { config } = await octokit.config.get({ |
| 232 | + owner, |
| 233 | + repo, |
| 234 | + path: ".github/test.yml", |
| 235 | + defaults(configs) { |
| 236 | + const allConfigs = [defaults, ...configs]; |
| 237 | + const fileSettingsConfigs = allConfigs.map( |
| 238 | + (config: Configuration) => config.settings |
| 239 | + ); |
| 240 | + return Object.assign({}, ...allConfigs, { |
| 241 | + settings: Object.assign({}, ...fileSettingsConfigs), |
| 242 | + }); |
| 243 | + }, |
| 244 | +}); |
| 245 | +``` |
| 246 | + |
| 247 | +Or simpler, using a library such as [deepmerge](https://github.com/TehShrike/deepmerge) |
| 248 | + |
| 249 | +```js |
| 250 | +const { config } = await octokit.config.get({ |
| 251 | + owner, |
| 252 | + repo, |
| 253 | + path: ".github/test.yml", |
| 254 | + defaults: (configs) => deepmerge([defaults, ...configs]), |
| 255 | +}); |
| 256 | +``` |
| 257 | + |
7 | 258 | ## Contributing
|
8 | 259 |
|
9 | 260 | See [CONTRIBUTING.md](CONTRIBUTING.md)
|
10 | 261 |
|
| 262 | +## Credits |
| 263 | + |
| 264 | +The idea for this plugin and some of its code was extracted from [Probot](https://probot.github.io/). It originated as [probot-config](https://github.com/probot/probot-config), created by [Jan Michael Auer](https://github.com/jan-auer) and was later merged into [`probot`](https://github.com/probot/probot). |
| 265 | + |
11 | 266 | ## License
|
12 | 267 |
|
13 |
| -[MIT](LICENSE) |
| 268 | +[ISC](LICENSE) |
0 commit comments