diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2610630 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +*.gem +*.rbc +*.swp +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +vendor/bundle +.idea +.ruby-version +.ruby-gemset diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2137940 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: ruby +rvm: + - 2.0 + - 2.1 + - 2.2 + - 2.3 + - 2.4.0 +before_install: gem update bundler diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f2e059f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,251 @@ +## Change Log + +### Unreleased + +### 4.1.0 (26/05/2017) +- Add appropriate Content-Type header (@mltsy) +- Add `Jobs` endpoint methods (@hjanuschka) +- Update `BuildTriggers` to v4 API and rename to `PipelineTriggers`. (@IgnoredAmbience) +- Add support for `keys` resource (@dirker) +- Remove version-lock for terminal-table (@SuperTux88) + +### 4.0.0 (10/04/2017) +- Adds ability to create commits in a repository - (@logicminds) +- Remove Ruby 1.x support from the project - (@orta) +- Add `star_project` and `unstar_project` methods. (@connorshea) +- Lock terminal-table to prevent build failures on Ruby 1.9/2.0. (@connorshea) +- Update documentation to link to docs.gitlab.com instead of the GitHub mirror for GitLab CE. (@connorshea) +- Add method `share_project_with_group` (@danhalligan) +- Allow to retrieve `ssh_keys` for a specific user(@dirker) +- Allow issues to use NAMESPACE/REPO identifier (@brodock) +- Add issues subscribe/unsubscribe (@newellista) +- Add merge_requests subscribe/unsubscribe (@newellista) +- Updated `deploy_key` endpoints (@epintozzi) +- Add milestone/merge_requests (API V4 only) (@joren) +- Rename "git hook" to "push rule". (@asedge) +- Change project fork endpoint for v4 API. (@asedge) +- Block/unblock user now uses POST instead of PUT. (@asedge) +- Project ID can also be a string (namespace/project_name). (@bergholdt) +- Support pipeline. (@bergholdt) +- Add methods to disable and enable deploy keys on projects. (@buzzdeee) +- Add method to fetch issues a merge request will close. (@joren) +- Fix `get_file` and `file_contents` methods to work with APIv4. (@asedge) + +### 3.7.0 (16/08/2016) + +- Add in GitlabCI Runner support (@davidcollum) +- Implemented tags API methods (@jblackman) +- Expose response status when Gitlab raises an error. (@calavera) +- Add `build_artifacts` method (@nanofi) +- Add `user_search` method (@Dreeg) +- Added project git hook support (@liger1978) +- Add the ability to delete an issue (@dandunckelman) +- Add missing Build APIs (@edgemaster) +- Improve record table output to use Hash `id` field if it exists. (@asedge) +- Support for listing merge request notes (@dlukman) +- Update YARD so it can be formatted easier for the CLI. (@asedge) +- Add `options` to `build` method (@sanderhahn) +- Add `delete_group` method (@shadeslayer) +- Add `group_projects` method (@shadeslayer) +- Add `edit_merge_request_comment` (@hjanuschka) +- Add `merge_request_commits` method (@nomeaning777) +- Add method `edit_group_member` (@coder-hugo) +- New builds endpoints (@kmarcisz) +- Use `respond_to_missing?` instead of `respond_to?` (@tsigo) +- Added possibility to change emails of user (@azomazo) +- Added possibility to change services in the project (@azomazo) +- Update README.md (@walterheck) + +### 3.6.1 (13/12/2015) + +- Fixed CLI output for collections + +### 3.6.0 (11/12/2015) + +- Improved output of the CLI help (@thomasdarimont) +- Added `search_projects` alias for `project_search` method +- Added pagination and auto pagination support (@nanofi) + +### 3.5.0 (26/11/2015) +- [a4f2150](https://github.com/NARKOZ/gitlab/commit/a4f21504a7288caace5b7433b49f49dc31e32b30) Add support for namespaces endpoint +- [3ad81a1](https://github.com/NARKOZ/gitlab/commit/3ad81a19a10b35ea422c0abcf08e6d03a325f4cd) Add missing "@" in doc. (@asedge) +- [fc34acb](https://github.com/NARKOZ/gitlab/commit/fc34acb6b475bb2555e4b035c11fdf42b3db4085) Add Gitlab::Client::Commits and rearrange methods and tests related to commits. (@asedge) +- [527089b](https://github.com/NARKOZ/gitlab/commit/527089b17fa7ed74a39b30dc6e8bb33482c1044b) Add commit status API, was added in Gitlab 8.1 (@dsander) +- [0a2f1db](https://github.com/NARKOZ/gitlab/commit/0a2f1dbe3efb66511dc836ef0ef884efedd70ef3) Add --json CLI parameter to output results as JSON +- [3f9cb62](https://github.com/NARKOZ/gitlab/commit/3f9cb625517c7294652139f2748e4bc7b98848cc) Adding sudo option for when forking a project (@gregoriomelo) +- [8dd964e](https://github.com/NARKOZ/gitlab/commit/8dd964ee743e051fade3137d8fac9bb387770150) Fix CLI configuration example comment line width to <= 80. (@asedge) +- [bbb8b61](https://github.com/NARKOZ/gitlab/commit/bbb8b61db46b32b8649956cb81d9a41e132493d4) Add comment for CLI configuration example. (@asedge) +- [30e96b9](https://github.com/NARKOZ/gitlab/commit/30e96b9444f7d60d4c0a56f57202c609497126eb) Update README.md (@raine) +- [d81f05b](https://github.com/NARKOZ/gitlab/commit/d81f05b80b7aaccef49641acfada3b2181f1633d) Change #handle_error method so it handles errors that are returned as an Array. (@asedge) +- [4c0395e](https://github.com/NARKOZ/gitlab/commit/4c0395ebc58c5a907489b6dc9dcac151e07b4dc8) Add Unprocessable error handler (@ondra-m) +- [3179bed](https://github.com/NARKOZ/gitlab/commit/3179bedc498b6c5577cc3c0b04633f67eb286ea9) Add block/unblock user. This API feature was added in GitLab 7.13 (@azomazo) +- [9946c7d](https://github.com/NARKOZ/gitlab/commit/9946c7d2a2c4261cbfc9c4a492b079c79abc2767) Check for specific exceptions in tests to suppress rspec warnings. (@asedge) +- [5e1c025](https://github.com/NARKOZ/gitlab/commit/5e1c025b8fdf723770c7c7ac0116acdf5cc9f2d5) Added support description option in create_group method (@azomazo) +- [46b657e](https://github.com/NARKOZ/gitlab/commit/46b657e47a29bc18f4122fff593a9eb58b73e4f1) deleting a gitlab project returns the string "true" (@tosmi) +- [cc3b489](https://github.com/NARKOZ/gitlab/commit/cc3b489cdeb3bd18b4ec841f80e76e74ddd0ce37) add development scripts (@NARKOZ) +- [24ad7fd](https://github.com/NARKOZ/gitlab/commit/24ad7fd2a1bd99eb468f1181d95c75fbec5d8fe0) Added specs edit_project, create_fork, create_user_with_username (@p404) +- [42e73a2](https://github.com/NARKOZ/gitlab/commit/42e73a2fde3e64dc8e3cf0ec73b8cfad88e43ca8) Added edit_project method to Projects module && updated the create_user method (@p404) +- [c9822f1](https://github.com/NARKOZ/gitlab/commit/c9822f1b61a8d7a5e855616e80e725730340cd48) Refactor create_user method (@p404) +- [6d7c4e7](https://github.com/NARKOZ/gitlab/commit/6d7c4e7c3285ee082513b3125346e6ed9c18b24b) Added create_fork method to Projects module (@p404) +- [54155b6](https://github.com/NARKOZ/gitlab/commit/54155b6c59d6e307744668cb3592ca98cf11d8f2) Add snippet_content method + tests. (@asedge) +- [cfff385](https://github.com/NARKOZ/gitlab/commit/cfff385b7f528223bf9ddc5f4177883e5ca56492) Remove executable permission on fixture file. (@asedge) +- [487a372](https://github.com/NARKOZ/gitlab/commit/487a372f7041d104975570747a63c9021881c952) Add RepositoryFiles#get_file method. (@asedge) +- [c9c05ad](https://github.com/NARKOZ/gitlab/commit/c9c05adee50828cc2e31048006cc95b5f2b9b7ce) Hide auth_token method from CLI/shell. (@asedge) +- [ef408a7](https://github.com/NARKOZ/gitlab/commit/ef408a7de0e677a568a66dbf212139aafc2e6186) Remove unnecessary require. (@asedge) +- [a2752d1](https://github.com/NARKOZ/gitlab/commit/a2752d1f5a01759a85d1e2003bb81c8e59cf85d3) Add some missing examples. (@asedge) +- [ac595af](https://github.com/NARKOZ/gitlab/commit/ac595af15a07601b3b657d4b4c1c479651aaa7d7) Add group_search method. (@asedge) +- [53a6671](https://github.com/NARKOZ/gitlab/commit/53a667184ed3640aefcb3f67836d37f58a504f24) Added Users#delete_user method (@cthulhu666) +- [a2360f0](https://github.com/NARKOZ/gitlab/commit/a2360f08019632c2660dbbc6753bd3094286b993) Add httparty ENV variable for CLI. Fixes #127. (@asedge) + +### 3.4.0 (22/04/2015) +- [9acb83d](https://github.com/NARKOZ/gitlab/commit/9acb83d2d068720b07934f5152313dc22a2f6374) remove check for missing attributes +- [8896e2b](https://github.com/NARKOZ/gitlab/commit/8896e2b7d5e8df509d48a411fd4440e27ed13995) return false when response body is empty +- [a04f3af](https://github.com/NARKOZ/gitlab/commit/a04f3af2d7aa8eec60c4f044fdb148e45c1ca133) escape ref parameter for repo_file_contents +- [8dcfec5](https://github.com/NARKOZ/gitlab/commit/8dcfec5aaaff9ef1c12687c5f9ca90f6aed0f912) Add tests for project_search. (@asedge) +- [75ead81](https://github.com/NARKOZ/gitlab/commit/75ead813b4335bab2464b6af0fb776c3d746242f) Added :page and :per_page query options to snippet_notes method (@StephenOTT) +- [f9818cb](https://github.com/NARKOZ/gitlab/commit/f9818cb121c8eeb9197e66732fec30ab90deecad) Added :page and :per_page query options to issue_notes method (@StephenOTT) +- [f92d745](https://github.com/NARKOZ/gitlab/commit/f92d745f1f561955d8fcbed4e23b43bb92ace255) Added :page and :per_page query options to notes method (@StephenOTT) +- [d4c3f20](https://github.com/NARKOZ/gitlab/commit/d4c3f2052c844486cf2b99a5346af4cd3fc001c9) Add support for merge_request_changes (@dsander) +- [2253fba](https://github.com/NARKOZ/gitlab/commit/2253fbab0a915d23f30de04a90167a0c783f9a6b) Allow authenticating via oauth with the private_token (@dsander) +- [8b7bcb4](https://github.com/NARKOZ/gitlab/commit/8b7bcb478e168f5ce2c94b8633b33128c29252b9) add inspect method to ObjectifiedHash +- [257737c](https://github.com/NARKOZ/gitlab/commit/257737c80ca93a71dfb5f8d990e5de1423603dfc) add delete_branch (@marc-ta) +- [f6532d5](https://github.com/NARKOZ/gitlab/commit/f6532d5074e0bb0d06bc251fb43b73f49a7af17a) improve docs +- [5164e6d](https://github.com/NARKOZ/gitlab/commit/5164e6de544bc34c57c3444e0b63cf3aada23776) Adding options hash to milestone_issues method. +- [57fa92d](https://github.com/NARKOZ/gitlab/commit/57fa92d7eef96e84498fa005e7ab83abc2a41a2b) Added support to get milestone issues. (@pbendersky) +- [d604e58](https://github.com/NARKOZ/gitlab/commit/d604e58732ea08fb15acdc1be339535e34e68d73) Add create_merge_request_note +- [cea19b8](https://github.com/NARKOZ/gitlab/commit/cea19b8e607033700dcab4648c05ac398cfe9566) Add project_search method (@ey3ball) +- [d0ebd3b](https://github.com/NARKOZ/gitlab/commit/d0ebd3b3a0ed83fc62d2a2e22ba9aa29a99cdcb6) Catch SIGINT earlier during shell session. Fixes #111. (@asedge) +- [2133562](https://github.com/NARKOZ/gitlab/commit/21335623009553197b61826d9894a739de152665) Redo the actions_table to make it more readable. CLI can now display the same help as the Shell. Closes #106. (@asedge) +- [da18909](https://github.com/NARKOZ/gitlab/commit/da1890949fb9eb60c13ab670dd8428d27de1814b) Add some method documentation and small style fixes. (@asedge) +- [7e1b408](https://github.com/NARKOZ/gitlab/commit/7e1b408e48152df1ce6e2be74a653c3801a37c10) Authenticate via oauth an auth_token (@dsander) +- [adb28b3](https://github.com/NARKOZ/gitlab/commit/adb28b30dab47bd3a58eae697d40e4aa346ea2c8) Update create_merge_request doc to include :target_project_id parameter. Closes #108. (@asedge) +- [525e913](https://github.com/NARKOZ/gitlab/commit/525e9131fe99a3f7396b547810e957058ab5a092) add ruby-2.2 to travis-ci +- [3671c89](https://github.com/NARKOZ/gitlab/commit/3671c89071d712ee71fa51cac67f3e0b9a28b03b) Save shell history when user presses Ctrl-d (@asedge) +- [c8e5f50](https://github.com/NARKOZ/gitlab/commit/c8e5f50684533e00550bfa4474062665000df28a) Hide httparty & httparty= methods from Gitlab.actions - just like endpoint, private_token, etc. (@asedge) +- [358deeb](https://github.com/NARKOZ/gitlab/commit/358deeb8ed849defe28c7cba84e1935d549fce22) Fix a regression with exception handling in shell. (@asedge) +- [9612ce3](https://github.com/NARKOZ/gitlab/commit/9612ce3b8274a385ce8c1fcd5ca5d0a0eba71c7e) Added support for repository files create, edit and remove. (@razielgn) +- [2203ad7](https://github.com/NARKOZ/gitlab/commit/2203ad7fcaa337da3d9700cbbc342d961be18eee) Fix headings in action_table. (@asedge) +- [b4dceb3](https://github.com/NARKOZ/gitlab/commit/b4dceb3d2d582682f3cb35ca63e41e237d222596) add CHANGELOG.md +- [e2bd91c](https://github.com/NARKOZ/gitlab/commit/e2bd91ccf488dfede7688801e54270da0d395a56) Small refactor of Gitlab::Help, Gitlab::Shell & Gitlab::CLI::Helpers. Add some new tests and refactor ones recently added. (@asedge) +- [bffd84f](https://github.com/NARKOZ/gitlab/commit/bffd84f4e9e37d056772536f33a52f40df0b7882) Refactor Gitlab::Help. Add tests some. (@asedge) +- [9bd4f7a](https://github.com/NARKOZ/gitlab/commit/9bd4f7ad69614ee009c351811deee9eb2a6c3d05) Add test for Gitlab::Shell. (@asedge) +- [bc14ec5](https://github.com/NARKOZ/gitlab/commit/bc14ec5173e432ced601c108cae6eca56026d41e) Refactor of Gitlab::Shell to hopefully make it more readable & testable. Wrote tests for some Gitlab::Shell & Gitlab::CLI::Helper methods. Other minor improvements and refactors. (@asedge) + +### 3.3.0 (22/12/2014) +- [42b4bc7](https://github.com/NARKOZ/gitlab/commit/42b4bc7b0e5e35f151ab61e27099606f0f38af31) fix docs and specs +- [04e39e0](https://github.com/NARKOZ/gitlab/commit/04e39e013a7a74f6101a97c3791da0594da232a3) ability to update hook triggers +- [6c66fe9](https://github.com/NARKOZ/gitlab/commit/6c66fe92a56cca58630a34ed3e7991517dd63604) remove useless check for available hook events +- [c4b981d](https://github.com/NARKOZ/gitlab/commit/c4b981dd69974aa7e1cb088c9b9fd44e0c0a9b54) add accept_merge_request method +- [51611fe](https://github.com/NARKOZ/gitlab/commit/51611fe669987cd9f4c1fac0ed96c743e391bbf2) Use endpoint instance var instead of base_uri class method. Fixes #94. (@asedge) +- [1ec8b38](https://github.com/NARKOZ/gitlab/commit/1ec8b38322657c3f97a60deb10dc08b828ba9875) test multiple clients +- [44d013a](https://github.com/NARKOZ/gitlab/commit/44d013af76535a2227678869148fb7a8195691df) Capture CTRL-C in Shell (@chrisdambrosio) +- [3cba3b2](https://github.com/NARKOZ/gitlab/commit/3cba3b2420d72d8aead0febf0ba3564c7615cf8c) Adding respond_to override to the ObjectifiedHash class so it properly responds to respond_to? calls (@koglinjg) +- [ce20c47](https://github.com/NARKOZ/gitlab/commit/ce20c4768c3e591b0cea72e8738371ab76d7289e) limit history file size - closes #93 (@chrisdambrosio) +- [1cf656f](https://github.com/NARKOZ/gitlab/commit/1cf656f7cf9f1821339b9e6ed711f6218cddbf0f) Save/load shell mode history - closes #79 (@chrisdambrosio) +- [727780b](https://github.com/NARKOZ/gitlab/commit/727780b8f282bb8fe461a54e558fe0775b4b36fd) HTTP proxy support - closes #52 (@chrisdambrosio) +- [e4ceb18](https://github.com/NARKOZ/gitlab/commit/e4ceb187aa5e47d20740676aea4f36c473ddd241) implement .file_contents (@chrisdambrosio) +- [0d0e7e0](https://github.com/NARKOZ/gitlab/commit/0d0e7e01bab1708cd85294788f9b9cca33a33ddb) Now must use YAML valid syntax in CLI or CLI Shell where Gitlab methods expect Hashes (usually in the form of options). (@asedge) +- [a7d0e0a](https://github.com/NARKOZ/gitlab/commit/a7d0e0a8c1c50c4ab43faccdb88f049f5b84a1cf) add CONTRIBUTING.md +- [1f4ef8e](https://github.com/NARKOZ/gitlab/commit/1f4ef8ed25ccd1bdbeccf677a0a94106903d0f24) improve docs +- [3a8d339](https://github.com/NARKOZ/gitlab/commit/3a8d33946adec71724304f661d70eb515a2f6848) Repository tree root level files (@semenyukdmitriy) +- [ddab89e](https://github.com/NARKOZ/gitlab/commit/ddab89e6aa9917d06cddd121aa486424753bdf84) Adds support for comments on commits (@jeroenj) +- [a7c18f1](https://github.com/NARKOZ/gitlab/commit/a7c18f1180157021ef8d24791f32a30511940fbf) Add labels api for list, create, edit and delete. (@artworx) +- [d9940d5](https://github.com/NARKOZ/gitlab/commit/d9940d5f4dfd8fdc4530b249b518e0d048dbfdbb) Support pagination in Gitlab.merge_request_comments (@cubiware) +- [13a550c](https://github.com/NARKOZ/gitlab/commit/13a550cb82a4775f3c72850dcd65e807abe46e69) Update tests for create_tags method so it more closely matches what will happen in Gitlab 7.5.0. (@asedge) +- [6d8a98f](https://github.com/NARKOZ/gitlab/commit/6d8a98f7930d2df5af19cc838eb95ae9c775e1a1) Add repo compare API (@zlx) +- [76e29e6](https://github.com/NARKOZ/gitlab/commit/76e29e632ce345ed17d69401dcb286dc85a951aa) Add support for annotated tag creation. Update tests for create_tag. (@asedge) +- [40295b8](https://github.com/NARKOZ/gitlab/commit/40295b8889c0094babffc81a5d7749d32b0fbda6) introduce HTTParty-configuration, fix #61 (@barraq) +- [916e8a7](https://github.com/NARKOZ/gitlab/commit/916e8a72371a097fa63065b05d3dca0be7bc9e93) Improved arg parsing for gitlab readline shell. Other small fixes/improvements on regexes. (@asedge) +- [382fe71](https://github.com/NARKOZ/gitlab/commit/382fe71e3d509a57f736138ffbb673695577f709) Add missing documentation: :group_id, :namespace_id (@arioch) +- [c9f9662](https://github.com/NARKOZ/gitlab/commit/c9f9662a9b1116c838b523ed64c6abdb4aae4b8b) add exit command to shell + +### 3.2.0 (22/06/2014) +- [fee67da](https://github.com/NARKOZ/gitlab/commit/fee67da36cdab7906004e7a060602eb342c8b946) Handling some error cases when calling for help. (@asedge) +- [7705b01](https://github.com/NARKOZ/gitlab/commit/7705b01c94d8833fb055ca072d34c0019c622caf) Adding online help for Gitlab::Shell using "ri" command. I'm unsure if this is the best idea. Some refactoring still needs to be done to remove duplicate code. (@asedge) +- [599deff](https://github.com/NARKOZ/gitlab/commit/599deffbe193aed420747be16516b29b8beeb31f) Fix output_table call in CLI. (@asedge) +- [4a5f81f](https://github.com/NARKOZ/gitlab/commit/4a5f81f0e605a89205c05a4baefdbf6d2331d667) Initial commit of Gitlab CLI shell. Tab completion for Gitlab.actions. (@asedge) +- [48ba2a1](https://github.com/NARKOZ/gitlab/commit/48ba2a178b0e3f206588ccd5aeed14e52d1ba269) fix specs after update to RSpec 3 +- [a8284af](https://github.com/NARKOZ/gitlab/commit/a8284af9af017e0bf381347a534f9a2426e35d64) Add spec for project_events method (@hassaku) +- [8e8527c](https://github.com/NARKOZ/gitlab/commit/8e8527cc4743a11ea285072e11f1bb4e703757ff) Add method to get a list of project events (@hassaku) +- [8c2aa8f](https://github.com/NARKOZ/gitlab/commit/8c2aa8fc9f660696596639d458444bc00fe17f0c) Add create_tag method. Add tests for new method. (@asedge) +- [cd5ae8b](https://github.com/NARKOZ/gitlab/commit/cd5ae8ba8aca5025a41ec1dd9fad70dae10c2fd3) clarify default config options + +### 3.1.0 (22/05/2014) +- [16834bb](https://github.com/NARKOZ/gitlab/commit/16834bb178fa6bf6c7ec8b67bfedfdc32145769d) add info command to CLI +- [68aebb7](https://github.com/NARKOZ/gitlab/commit/68aebb76b24972b7d00a78f3d4f923fca009ba31) ability to delete a project +- [ac54e55](https://github.com/NARKOZ/gitlab/commit/ac54e55825d16373862fbbc176d6c9c2594dc593) set command arguments when no filters +- [23be13e](https://github.com/NARKOZ/gitlab/commit/23be13e87c3c99764fcb27393ce99d9cc05633b9) fix docs +- [1b298dc](https://github.com/NARKOZ/gitlab/commit/1b298dcd5f71321867ad2bd3c18522a7602357ad) fix ruby 1.9 compatibility +- [af92ff5](https://github.com/NARKOZ/gitlab/commit/af92ff546af578ba0753c254fabf73761553f4c8) add confirmation for destructive commands +- [b1602d2](https://github.com/NARKOZ/gitlab/commit/b1602d2f5ce0a614de48d5295654d0699fe69c0d) move methods related to CLI output to a separate module +- [4183a52](https://github.com/NARKOZ/gitlab/commit/4183a52ca6344d86aa152e189bc20c467c96c5a5) improve help message +- [0bba284](https://github.com/NARKOZ/gitlab/commit/0bba284e9447a4a6aa95990b65db5ae4d44ce989) add specs for CLI +- [5ec08bc](https://github.com/NARKOZ/gitlab/commit/5ec08bc0173e986e5979ca0c809d70002186f0cc) ability to filter CLI output +- [ba86169](https://github.com/NARKOZ/gitlab/commit/ba861692bae33cba8d22ac3beb223995a4df216c) add table output for multiple records +- [9cc540c](https://github.com/NARKOZ/gitlab/commit/9cc540c948bd71a70e3c1f6fc656e1bbde0dcb00) initial wrap-up of CLI +- [bee9745](https://github.com/NARKOZ/gitlab/commit/bee9745f2202f9dafd20b0edee185fe54f413cb2) include modules alphabetically +- [4963f16](https://github.com/NARKOZ/gitlab/commit/4963f16f3eb0a3f3a6dd7fbdc3b7f3aeab8d57cc) add special method that lists available actions for client +- [fe50c24](https://github.com/NARKOZ/gitlab/commit/fe50c24437ea2bd729044f30ef6afe8df1932f32) support environment variables +- [7a5d40c](https://github.com/NARKOZ/gitlab/commit/7a5d40ccd576abfb35c137f9e172821351d2dac8) eliminate ruby warning +- [b7fc447](https://github.com/NARKOZ/gitlab/commit/b7fc447211fe281e01f111f8a9fad08396fdfa4d) convert specs to new RSpec 2.14 syntax +- [471a643](https://github.com/NARKOZ/gitlab/commit/471a643a60a17ea9048615a2ac2d295e0682edd4) pass private token using HTTP headers +- [bbf6521](https://github.com/NARKOZ/gitlab/commit/bbf6521362d5af460c63a730d95f822e55160e82) fix users session spec +- [672a8d5](https://github.com/NARKOZ/gitlab/commit/672a8d54988dfafce4e3288a63f6cf67bf13c292) test Request class +- [3bf0363](https://github.com/NARKOZ/gitlab/commit/3bf03631769a419504f669bd3154953072701c61) set private_token param separately for each request +- [90760cd](https://github.com/NARKOZ/gitlab/commit/90760cdeb3dfaa7be5fdfa5eba792c3a8e617c57) Single commit and diff of a commit (@nanofi) +- [9b696d4](https://github.com/NARKOZ/gitlab/commit/9b696d4bd07c1ca5d8d41e6aaeb51f260393b789) pluralize module name: SystemHook -> SystemHooks +- [3b2cda9](https://github.com/NARKOZ/gitlab/commit/3b2cda9e974568f8d1d6bfebbf3f114686638f44) get rid of ruby argument prefix warning +- [0d6ca05](https://github.com/NARKOZ/gitlab/commit/0d6ca0565ee0eaf02ae077332f8082c8d939ce22) System Hook API (@nanofi) +- [29e31e0](https://github.com/NARKOZ/gitlab/commit/29e31e0a565a083c22401bb99b3cb28c8a43f5d6) Create branches.rb. Move branch related actions there. Add new methods for (un)protecting branches and creating new branches - which requires Gitlab 6.8-stable or newer. Added tests for new methods and fixed old tests looking for methods in old locations. (@asedge) +- [7f91a9a](https://github.com/NARKOZ/gitlab/commit/7f91a9a10dc8071d14d3ffaea001e32ac2f70180) Fixed: create project deploy key (@semenyukdmitriy) +- [b347574](https://github.com/NARKOZ/gitlab/commit/b3475743c624e7cc426ca099f0c86411ffaf6dd8) Project hooks: set events to trigger on (@semenyukdmitriy) +- [af49245](https://github.com/NARKOZ/gitlab/commit/af492453819678eca9f2a8e25b51d318e23d148c) Add merge_request_comments to get a MR's comments +- [2b9e659](https://github.com/NARKOZ/gitlab/commit/2b9e659afd646f8ffca7b323e40246096837eae7) Doc & test that update_merge_request can set state +- [45b0b9f](https://github.com/NARKOZ/gitlab/commit/45b0b9fc86016ba31e66b600172da6ace63f7a00) add 'to_hash' method for ObjectifiedHash +- [ce5294f](https://github.com/NARKOZ/gitlab/commit/ce5294f2ec74417626403595899a85c97d92318c) test against MRI 2.1.0 +- [35aadef](https://github.com/NARKOZ/gitlab/commit/35aadef3f321d4d700c3f7926f2206ac241e7191) scope for projects api (@voanhduy1512) +- [7152c85](https://github.com/NARKOZ/gitlab/commit/7152c8520bf77f49385bb71ef82a574172500b00) Add edit_user method (@robertomiranda) + +### 3.0.0 (22/10/2013) +- [da31730](https://github.com/NARKOZ/gitlab/commit/da3173016870d76aabbd43ee1b04e7348cbdbb1e) handle response code 405 +- [3c18ad0](https://github.com/NARKOZ/gitlab/commit/3c18ad0d373b4647232be3bbc1ee88aed9a3bbfc) remove ruby 1.8 patch +- [3fca003](https://github.com/NARKOZ/gitlab/commit/3fca0033e8dabbefdbf50fc15713866521d0e1d3) re-implement handling of sudo requests +- [49c54a6](https://github.com/NARKOZ/gitlab/commit/49c54a67a8c1a67dd1f471c93e63c6dace329817) ability to paginate group members +- [8ba8361](https://github.com/NARKOZ/gitlab/commit/8ba8361d6fed3967986243a9c48871b79040bb51) fix compatibility with API v3; update docs +- [93e8b81](https://github.com/NARKOZ/gitlab/commit/93e8b81632067879d874a31e18ab48a50ccaf05c) prettify error message +- [1752997](https://github.com/NARKOZ/gitlab/commit/1752997f22586c76929c7396db8892fe930cb93a) Add methods to manage deployment keys (@sosedoff) +- [613dda8](https://github.com/NARKOZ/gitlab/commit/613dda8f7b42770635023137fb6844709ad77ffd) Add group api, removed user_teams api +- [8db4e88](https://github.com/NARKOZ/gitlab/commit/8db4e88ade68401e3e2dc26f8cc9b78a48a0f8ea) Update error_message to print request uri on response failure +- [dd33a2f](https://github.com/NARKOZ/gitlab/commit/dd33a2feaa96022d6bd3795fb861eaf57f554bfa) Adding a check_attributes method in order to verify that the correct parameters have been passed into create_merge_request and comment_merge_request. Updating tests. (@thomasbiddle) +- [6f4a170](https://github.com/NARKOZ/gitlab/commit/6f4a170191a401c7eaf97522c5b8e20970e90249) Adding tests for missing merge request api calls. (@thomasbiddle) +- [af42bcb](https://github.com/NARKOZ/gitlab/commit/af42bcb7c18b27db266efdf7c9645d795d691760) Adding support for creating, updating, and commenting on merge requests. (@thomasbiddle) +- [f7aac38](https://github.com/NARKOZ/gitlab/commit/f7aac3860169ce0d0268676dc278d8150e497df8) minor updates indicating support for creating public projects (@amacarthur) +- [44a090d](https://github.com/NARKOZ/gitlab/commit/44a090d983de178ebdc7f6cd9cdcc339d731f9ef) added apis for the admin of fork links (@amacarthur) +- [32f1419](https://github.com/NARKOZ/gitlab/commit/32f14199c53da58ce00572530a002f769c808024) Added sudo functionality +- [b7f6c48](https://github.com/NARKOZ/gitlab/commit/b7f6c48b65b4d18cc18919fab12cefa99826578e) Made 409's throw exceptions +- [d1f581f](https://github.com/NARKOZ/gitlab/commit/d1f581ff410ba5c42d03e2cf98efa548a6139b01) Fixed an issue with access level var in add team project +- [8a5d679](https://github.com/NARKOZ/gitlab/commit/8a5d679806bd1dc8501965450fe12d0e807fbd93) Add user_team api +- [b4444fc](https://github.com/NARKOZ/gitlab/commit/b4444fce8c3dd9f0caa2d1a096e61ce6373136fe) Adding user_teams api +- [53d7a8a](https://github.com/NARKOZ/gitlab/commit/53d7a8a86dfed63e56eeb16ea496bb7a82de337e) consistently refer to feature as "project for user" per documentation @ https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md#create-project-for-user (@dylee) +- [13457a4](https://github.com/NARKOZ/gitlab/commit/13457a4bfd67088e156489d09db148739a0af700) add support for POST /projects/user:user_id (@leesolutions) +- [5e556fa](https://github.com/NARKOZ/gitlab/commit/5e556fac11daa25d3d9683904cf8f96b8e0bb009) update travis-ci config with ruby-2.0 +- [3b8513d](https://github.com/NARKOZ/gitlab/commit/3b8513da22c8d78ce6a284ac8a7a5eaad6ab349d) Groups api additions +- [f2ba111](https://github.com/NARKOZ/gitlab/commit/f2ba111dba70eca5346a880c541dafaf35d3332a) don't expose data in ObjectifiedHash +- [c6889eb](https://github.com/NARKOZ/gitlab/commit/c6889ebfd455892690c0cddc3b88c670d8723435) add specs for notes +- [e562a7d](https://github.com/NARKOZ/gitlab/commit/e562a7db8ffdf9ec947895800e9c5b7753b83bfb) bring support for ruby 1.8 +- [63c3592](https://github.com/NARKOZ/gitlab/commit/63c3592af45aa0d01de09910f562a4f875d01f6a) Notes api for wall, issues, and snippets notes. List, read and create. (@jozefvaclavik) + +### 2.2.0 (22/11/2012) +- [2ef4d48](https://github.com/NARKOZ/gitlab/commit/2ef4d48a0db13a7363973455c3c0ac9d2bf6df56) support merge requests API + +### 2.1.0 (22/10/2012) +- [89541c1](https://github.com/NARKOZ/gitlab/commit/89541c1dddccf185318645bb2748541955f221b0) add ability to create a user +- [483b4f6](https://github.com/NARKOZ/gitlab/commit/483b4f6812e657e9ea12c0c89199654393554aa7) fix typos in docs +- [7632ecb](https://github.com/NARKOZ/gitlab/commit/7632ecba57c8fa3fe966ee6eb0055bb7752d79fd) add ability to list project snippets +- [6c5637e](https://github.com/NARKOZ/gitlab/commit/6c5637e526f73bfb1c7791b12756ebdadeae4e5f) add project_hook and edit_project_hook methods +- [5fcf078](https://github.com/NARKOZ/gitlab/commit/5fcf078437b62a39de7d49c6d92fd5cdf09c565c) Fix add_team_member (@mizzy) +- [6a0176a](https://github.com/NARKOZ/gitlab/commit/6a0176aac542eacd9df24da20a8994f9f70e6ed7) refactor Request class +- [53746d5](https://github.com/NARKOZ/gitlab/commit/53746d55f19f75e72b3439d25f7940ba66151c94) add convenient methods to change a state of an issue + +### 2.0.0 (21/09/2012) +- [b47a324](https://github.com/NARKOZ/gitlab/commit/b47a324d616b7fa4e23160abae357887b9dde13f) initial implementation diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..99e6542 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,195 @@ +# Contributing to Gitlab + +Please take a moment to review this document in order to make the contribution +process easy and effective for everyone involved! + +## Using the issue tracker + +You can use the issues tracker for: + +* [bug reports](#bug-reports) +* [feature requests](#feature-requests) +* [submitting pull requests](#pull-requests) + +Use [Stackoverflow](http://stackoverflow.com/) for questions and personal support requests. + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + `master` branch in the repository. + +3. **Isolate and report the problem** — ideally create a reduced test + case. + +Please try to be as detailed as possible in your report. Include information about +your Ruby, Gitlab client and GitLab instance versions. Please provide steps to +reproduce the issue as well as the outcome you were expecting! All these details +will help developers to fix any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the environment in which it occurs. If suitable, +> include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the community of the merits of this feature. +Please provide as much detail and context as possible. + +## Contributing Documentation + +Code documentation has a special convention: it uses [YARD](http://yardoc.org/) +formatting and the first paragraph is considered to be a short summary. + +For methods say what it will do. For example write something like: + +```ruby +# Reverses the contents of a String or IO object. +# +# @param [String, #read] contents the contents to reverse +# @return [String] the contents reversed lexically +def reverse(contents) + contents = contents.read if contents.respond_to? :read + contents.reverse +end +``` + +For classes, modules say what it is. For example write something like: + +```ruby +# Defines methods related to groups. +module Groups +``` + +Keep in mind that the documentation notes might show up in a summary somewhere, +long texts in the documentation notes create very ugly summaries. As a rule of thumb +anything longer than 80 characters is too long. + +Try to keep unnecessary details out of the first paragraph, it's only there to +give a user a quick idea of what the documented "thing" does/is. The rest of the +documentation notes can contain the details, for example parameters and what +is returned. + +If possible include examples. For example: + +```ruby +# Gets information about a project. +# +# @example +# Gitlab.project(3) +# Gitlab.project('gitlab') +# +# @param [Integer, String] id The ID or name of a project. +# @return [Gitlab::ObjectifiedHash] +def project(id) +``` + +This makes it easy to test the examples so that they don't go stale and examples +are often a great help in explaining what a method does. + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +**IMPORTANT**: By submitting a patch, you agree that your work will be +licensed under the license used by the project. + +If you have any large pull request in mind (e.g. implementing features, +refactoring code, etc), **please ask first** otherwise you risk spending +a lot of time working on something that the project's developers might +not want to merge into the project. + +Please adhere to the coding conventions in the project (indentation, +accurate comments, etc.) and don't forget to add your own tests and +documentation. When working with git, we recommend the following process +in order to craft an excellent pull request: + +1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork, + and configure the remotes: + + ```sh + # Clone your fork of the repo into the current directory + git clone https://github.com//gitlab + # Navigate to the newly cloned directory + cd gitlab + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/NARKOZ/gitlab + ``` + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout master + git pull upstream master + ``` + +3. Create a new topic branch (off of `master`) to contain your feature, change, + or fix. + + **IMPORTANT**: Making changes in `master` is discouraged. You should always + keep your local `master` in sync with upstream `master` and make your + changes in topic branches. + + ```sh + git checkout -b + ``` + +4. Commit your changes in logical chunks. Keep your commit messages organized, + with a short description in the first line and more detailed information on + the following lines. Feel free to use Git's + [interactive rebase](https://help.github.com/articles/about-git-rebase/) + feature to tidy up your commits before making them public. + +5. Make sure all the tests are still passing. + + ```sh + rake + ``` + +6. Push your topic branch up to your fork: + + ```sh + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) + with a clear title and description. + +8. If you haven't updated your pull request for a while, you should consider + rebasing on master and resolving any conflicts. + + **IMPORTANT**: _Never ever_ merge upstream `master` into your branches. You + should always `git rebase` on `master` to bring your changes up to date when + necessary. + + ```sh + git checkout master + git pull upstream master + git checkout + git rebase master + ``` + +Thank you for your contributions! diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..54fbdf1 --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in gitlab.gemspec +gemspec diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..881faef --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,24 @@ +Copyright (c) 2012-2015 Nihad Abbasov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..510b407 --- /dev/null +++ b/README.md @@ -0,0 +1,186 @@ +# Gitlab + +[![Build Status](https://img.shields.io/travis/NARKOZ/gitlab.svg?style=flat)](https://travis-ci.org/NARKOZ/gitlab) +[![Code Climate](https://img.shields.io/codeclimate/github/NARKOZ/gitlab.svg?style=flat)](https://codeclimate.com/github/NARKOZ/gitlab) +[![Inline docs](http://inch-ci.org/github/NARKOZ/gitlab.svg?style=flat)](https://inch-ci.org/github/NARKOZ/gitlab) +[![Gem version](https://img.shields.io/gem/v/gitlab.svg?style=flat)](https://rubygems.org/gems/gitlab) +[![License](https://img.shields.io/badge/license-BSD-red.svg?style=flat)](https://github.com/NARKOZ/gitlab/blob/master/LICENSE.txt) + +[website](http://narkoz.github.io/gitlab) | +[documentation](http://rubydoc.info/gems/gitlab/frames) | +[gitlab-live](https://github.com/NARKOZ/gitlab-live) + +Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://docs.gitlab.com/ce/api/README.html). +As of version `4.0.0` this gem will only support Ruby 2.0+ and Gitlab API v4. + +## Installation + +Install it from rubygems: + +```sh +gem install gitlab +``` + +Or add to a Gemfile: + +```ruby +gem 'gitlab' +# gem 'gitlab', github: 'NARKOZ/gitlab' +``` + +## Usage + +Configuration example: + +```ruby +Gitlab.configure do |config| + config.endpoint = 'https://example.net/api/v4' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] + config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token or OAuth2 access token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] + # Optional + # config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]' + # config.sudo = 'user' # username for sudo mode, default: nil +end +``` + +(Note: If you are using GitLab.com's hosted service, your endpoint will be `https://gitlab.com/api/v4`) + +Usage examples: + +```ruby +# set an API endpoint +Gitlab.endpoint = 'http://example.net/api/v4' +# => "http://example.net/api/v4" + +# set a user private token +Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG' +# => "qEsq1pt6HJPaNciie3MG" + +# configure a proxy server +Gitlab.http_proxy('proxyhost', 8888) +# proxy server w/ basic auth +Gitlab.http_proxy('proxyhost', 8888, 'proxyuser', 'strongpasswordhere') + +# list projects +Gitlab.projects(per_page: 5) +# => [#1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>] + +# initialize a new client +g = Gitlab.client(endpoint: 'https://api.example.com', private_token: 'qEsq1pt6HJPaNciie3MG') +# => # + +# get a user +user = g.user +# => #1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}> + +# get a user's email +user.email +# => "john@example.com" + +# set a sudo mode to perform API calls as another user +Gitlab.sudo = 'other_user' +# => "other_user" + +# disable a sudo mode +Gitlab.sudo = nil +# => nil + +# a paginated response +projects = Gitlab.projects(per_page: 5) + +# check existence of the next page +projects.has_next_page? + +# retrieve the next page +projects.next_page + +# iterate all projects +projects.auto_paginate do |project| + # do something +end + +# retrieve all projects as an array +projects.auto_paginate +``` + +For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames). + +## CLI + +It is possible to use this gem as a command line interface to gitlab. In order to make that work you need to set a few environment variables: +```sh +export GITLAB_API_ENDPOINT=https://gitlab.yourcompany.com/api/v4 +export GITLAB_API_PRIVATE_TOKEN= +# This one is optional and can be used to set any HTTParty option you may need +# using YAML hash syntax. For example, this is how you would disable SSL +# verification (useful if using a self-signed cert). +export GITLAB_API_HTTPARTY_OPTIONS="{verify: false}" +``` + +Usage: + +When you want to know which CLI commands are supported, take a look at the client [commands implemented in this gem](http://www.rubydoc.info/gems/gitlab/3.4.0/Gitlab/Client). Any of those methods can be called as a command by passing the parameters of the commands as parameters of the CLI. + +Usage examples: + +```sh +# list users +# see: http://www.rubydoc.info/gems/gitlab/3.4.0/Gitlab/Client/Users#users-instance_method +gitlab users + +# get current user +# see: http://www.rubydoc.info/gems/gitlab/3.4.0/Gitlab/Client/Users#user-instance_method +gitlab user + +# get a user +# see: http://www.rubydoc.info/gems/gitlab/3.4.0/Gitlab/Client/Users#user-instance_method +gitlab user 2 + +# filter output +gitlab user --only=id,username + +gitlab user --except=email,bio + +# get a user and render result as json +gitlab user 2 --json + +# passing options hash to a command (use YAML) +# see: http://www.rubydoc.info/gems/gitlab/3.4.0/Gitlab/Client/MergeRequests#create_merge_request-instance_method +gitlab create_merge_request 4 "New merge request" "{source_branch: 'new_branch', target_branch: 'master', assignee_id: 42}" + +``` + +## CLI Shell + +Usage examples: + +```sh +# start shell session +gitlab shell + +# list available commands +gitlab> help + +# list groups +gitlab> groups + +# protect a branch +gitlab> protect_branch 1 master + +# passing options hash to a command (use YAML) +gitlab> create_merge_request 4 "New merge request" "{source_branch: 'new_branch', target_branch: 'master', assignee_id: 42}" +``` + +Web version is available at https://gitlab-live.herokuapp.com +For more information, refer to [website](http://narkoz.github.io/gitlab). + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run +`rake spec` to run the tests. You can also run `bin/console` for an interactive +prompt that will allow you to experiment. + +For more information see [CONTRIBUTING.md](https://github.com/NARKOZ/gitlab/blob/master/CONTRIBUTING.md). + +## License + +Released under the BSD 2-clause license. See LICENSE.txt for details. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..849ce04 --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require "bundler/gem_tasks" + +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new(:spec) do |spec| + spec.pattern = FileList['spec/**/*_spec.rb'] + spec.rspec_opts = ['--color', '--format d'] +end + +task default: :spec diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..1b231af --- /dev/null +++ b/bin/console @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +# ENV['GITLAB_API_ENDPOINT'] = '' +# ENV['GITLAB_API_PRIVATE_TOKEN'] = '' + +require 'bundler/setup' +require 'gitlab' +require 'pry' + +Pry.start diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..5b3a4e7 --- /dev/null +++ b/bin/setup @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail +IFS=$'\n\t' + +bundle install && + echo 'NOTE: You may need to set GITLAB_API_ENDPOINT and GITLAB_API_PRIVATE_TOKEN environment variables.' diff --git a/exe/gitlab b/exe/gitlab new file mode 100755 index 0000000..7d4c31c --- /dev/null +++ b/exe/gitlab @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) + +require 'gitlab/cli' + +Gitlab::CLI.start(ARGV) diff --git a/gitlab.gemspec b/gitlab.gemspec new file mode 100644 index 0000000..7700c83 --- /dev/null +++ b/gitlab.gemspec @@ -0,0 +1,31 @@ +# -*- encoding: utf-8 -*- +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'gitlab/version' + +Gem::Specification.new do |gem| + gem.name = "gitlab" + gem.version = Gitlab::VERSION + gem.authors = ["Nihad Abbasov"] + gem.email = ["mail@narkoz.me"] + gem.description = %q{Ruby client and CLI for GitLab API} + gem.summary = %q{A Ruby wrapper and CLI for the GitLab API} + gem.homepage = "https://github.com/narkoz/gitlab" + + gem.files = `git ls-files`.split($/) + gem.bindir = "exe" + gem.executables = gem.files.grep(%r{^exe/}) { |f| File.basename(f) } + gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + gem.require_paths = ["lib"] + gem.license = "BSD" + + gem.required_ruby_version = ">= 2.0.0" + + gem.add_runtime_dependency 'httparty' + gem.add_runtime_dependency 'terminal-table' + + gem.add_development_dependency 'pry' + gem.add_development_dependency 'rake' + gem.add_development_dependency 'rspec' + gem.add_development_dependency 'webmock' +end diff --git a/lib/gitlab/api.rb b/lib/gitlab/api.rb new file mode 100644 index 0000000..f04a56f --- /dev/null +++ b/lib/gitlab/api.rb @@ -0,0 +1,19 @@ +module Gitlab + # @private + class API < Request + # @private + attr_accessor(*Configuration::VALID_OPTIONS_KEYS) + # @private + alias_method :auth_token=, :private_token= + + # Creates a new API. + # @raise [Error:MissingCredentials] + def initialize(options={}) + options = Gitlab.options.merge(options) + (Configuration::VALID_OPTIONS_KEYS + [:auth_token]).each do |key| + send("#{key}=", options[key]) if options[key] + end + set_request_defaults(@sudo) + end + end +end diff --git a/lib/gitlab/cli.rb b/lib/gitlab/cli.rb new file mode 100644 index 0000000..e20607b --- /dev/null +++ b/lib/gitlab/cli.rb @@ -0,0 +1,89 @@ +require 'gitlab' +require 'terminal-table/import' +require_relative 'cli_helpers' +require_relative 'shell' + +class Gitlab::CLI + extend Helpers + + # If set to true, JSON will be rendered as output + @render_json = false + + # Starts a new CLI session. + # + # @example + # Gitlab::CLI.start(['help']) + # Gitlab::CLI.start(['help', 'issues']) + # + # @param [Array] args The command and it's optional arguments. + def self.start(args) + command = args.shift.strip rescue 'help' + run(command, args) + end + + # Processes a CLI command and outputs a result to the stream (stdout). + # + # @example + # Gitlab::CLI.run('help') + # Gitlab::CLI.run('help', ['issues']) + # + # @param [String] cmd The name of a command. + # @param [Array] args The optional arguments for a command. + # @return [nil] + def self.run(cmd, args=[]) + case cmd + when 'help' + puts help(args.shift) { |out| out.gsub!(/Gitlab\./, 'gitlab ') } + when 'info' + endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set' + private_token = Gitlab.private_token ? Gitlab.private_token : 'not set' + puts "Gitlab endpoint is #{endpoint}" + puts "Gitlab private token is #{private_token}" + puts "Ruby Version is #{RUBY_VERSION}" + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when '-v', '--version' + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when 'shell' + Gitlab::Shell.start + else + if args.include? '--json' + @json_output = true + args.delete '--json' + end + + unless valid_command?(cmd) + puts "Unknown command. Run `gitlab help` for a list of available commands." + exit(1) + end + + if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except=')) + command_args = args[0..-2] + else + command_args = args + end + + begin + command_args.map! { |arg| symbolize_keys(yaml_load(arg)) } + rescue => e + puts e.message + exit 1 + end + + confirm_command(cmd) + + data = gitlab_helper(cmd, command_args) { exit(1) } + + render_output(cmd, args, data) + end + end + + # Helper method that checks whether we want to get the output as json + # @return [nil] + def self.render_output(cmd, args, data) + if @json_output + output_json(cmd, args, data) + else + output_table(cmd, args, data) + end + end +end diff --git a/lib/gitlab/cli_helpers.rb b/lib/gitlab/cli_helpers.rb new file mode 100644 index 0000000..1b69e6f --- /dev/null +++ b/lib/gitlab/cli_helpers.rb @@ -0,0 +1,241 @@ +require 'yaml' +require 'json' +require 'base64' + +class Gitlab::CLI + # Defines methods related to CLI output and formatting. + module Helpers + extend self + + # Returns actions available to CLI & Shell + # + # @return [Array] + def actions + @actions ||= Gitlab.actions + end + + # Returns Gitlab::Client instance + # + # @return [Gitlab::Client] + def client + @client ||= Gitlab::Client.new(endpoint: (Gitlab.endpoint || '')) + end + + # Returns method names and their owners + # + # @return [Array] + def method_owners + @method_owners ||= actions.map do |action| + { + name: action.to_s, + owner: client.method(action).owner.to_s + } + end + end + + # Returns filtered required fields. + # + # @return [Array] + def required_fields(args) + if args.any? && args.last.is_a?(String) && args.last.start_with?('--only=') + args.last.gsub('--only=', '').split(',') + else + [] + end + end + + # Returns filtered excluded fields. + # + # @return [Array] + def excluded_fields(args) + if args.any? && args.last.is_a?(String) && args.last.start_with?('--except=') + args.last.gsub('--except=', '').split(',') + else + [] + end + end + + # Confirms command is valid. + # + # @return [Boolean] + def valid_command?(cmd) + command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym + Gitlab.actions.include?(command) + end + + # Confirms command with a desctructive action. + # + # @return [String] + def confirm_command(cmd) + if cmd.start_with?('remove_') || cmd.start_with?('delete_') + puts "Are you sure? (y/n)" + if %w(y yes).include?($stdin.gets.to_s.strip.downcase) + puts 'Proceeding..' + else + puts 'Command aborted.' + exit(1) + end + end + end + + # Gets defined help for a specific command/action. + # + # @return [String] + def help(cmd=nil, &block) + if cmd.nil? || Gitlab::Help.help_map.key?(cmd) + Gitlab::Help.actions_table(cmd) + else + Gitlab::Help.get_help(cmd, &block) + end + end + + # Outputs a nicely formatted table or error msg. + def output_table(cmd, args, data) + case data + when Gitlab::ObjectifiedHash, Gitlab::FileResponse + puts record_table([data], cmd, args) + when Gitlab::PaginatedResponse + puts record_table(data, cmd, args) + else # probably just an error msg + puts data + end + end + + def output_json(cmd, args, data) + if data.empty? + puts '{}' + else + hash_result = case data + when Gitlab::ObjectifiedHash,Gitlab::FileResponse + record_hash([data], cmd, args, true) + when Gitlab::PaginatedResponse + record_hash(data, cmd, args) + else + { cmd: cmd, data: data, args: args } + end + puts JSON.pretty_generate(hash_result) + end + end + + # Table to display records. + # + # @return [Terminal::Table] + def record_table(data, cmd, args) + return 'No data' if data.empty? + + arr, keys = get_keys(args, data) + + table do |t| + t.title = "Gitlab.#{cmd} #{args.join(', ')}" + t.headings = keys + + arr.each_with_index do |hash, index| + values = [] + + keys.each do |key| + case value = hash[key] + when Hash + value = value.has_key?('id') ? value['id'] : 'Hash' + when StringIO + value = 'File' + when nil + value = 'null' + end + + values << value + end + + t.add_row values + t.add_separator unless arr.size - 1 == index + end + end + end + + # Renders the result of given commands and arguments into a Hash + # + # @param [Array] data Resultset from the API call + # @param [String] cmd The command passed to the API + # @param [Array] args Options passed to the API call + # @param [bool] single_value If set to true, a single result should be returned + # @return [Hash] Result hash + def record_hash(data, cmd, args, single_value=false) + if data.empty? + result = nil + else + arr, keys = get_keys(args, data) + result = [] + arr.each do |hash| + row = {} + + keys.each do |key| + case hash[key] + when Hash + row[key] = 'Hash' + when StringIO + row[key] = Base64.encode64(hash[key].read) + when nil + row[key] = nil + else + row[key] = hash[key] + end + end + + result.push row + end + result = result[0] if single_value && result.count > 0 + end + + { + cmd: "Gitlab.#{cmd} #{args.join(', ')}".strip, + result: result + } + end + + # Helper function to get rows and keys from data returned from API call + def get_keys(args, data) + arr = data.map(&:to_h) + keys = arr.first.keys.sort { |x, y| x.to_s <=> y.to_s } + keys &= required_fields(args) if required_fields(args).any? + keys -= excluded_fields(args) + [arr, keys] + end + + # Helper function to call Gitlab commands with args. + def gitlab_helper(cmd, args=[]) + begin + data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd) + rescue => e + puts e.message + yield if block_given? + end + + data + end + + # Convert a hash (recursively) to use symbol hash keys + # @return [Hash] + def symbolize_keys(hash) + if hash.is_a?(Hash) + hash = hash.each_with_object({}) do |(key, value), newhash| + begin + newhash[key.to_sym] = symbolize_keys(value) + rescue NoMethodError + raise "error: cannot convert hash key to symbol: #{key}" + end + end + end + + hash + end + + # YAML::load on a single argument + def yaml_load(arg) + begin + yaml = YAML.load(arg) + rescue Psych::SyntaxError + raise "error: Argument is not valid YAML syntax: #{arg}" + end + yaml + end + end +end diff --git a/lib/gitlab/client/branches.rb b/lib/gitlab/client/branches.rb new file mode 100644 index 0000000..1249a86 --- /dev/null +++ b/lib/gitlab/client/branches.rb @@ -0,0 +1,91 @@ +class Gitlab::Client + # Defines methods related to repositories. + # @see https://docs.gitlab.com/ce/api/branches.html + module Branches + # Gets a list of project repositiory branches. + # + # @example + # Gitlab.branches(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def branches(project, options={}) + get("/projects/#{url_encode project}/repository/branches", query: options) + end + alias_method :repo_branches, :branches + + # Gets information about a repository branch. + # + # @example + # Gitlab.branch(3, 'api') + # Gitlab.repo_branch(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def branch(project, branch) + get("/projects/#{url_encode project}/repository/branches/#{branch}") + end + alias_method :repo_branch, :branch + + # Protects a repository branch. + # + # @example + # Gitlab.protect_branch(3, 'api') + # Gitlab.repo_protect_branch(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def protect_branch(project, branch) + put("/projects/#{url_encode project}/repository/branches/#{branch}/protect") + end + alias_method :repo_protect_branch, :protect_branch + + # Unprotects a repository branch. + # + # @example + # Gitlab.unprotect_branch(3, 'api') + # Gitlab.repo_unprotect_branch(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def unprotect_branch(project, branch) + put("/projects/#{url_encode project}/repository/branches/#{branch}/unprotect") + end + alias_method :repo_unprotect_branch, :unprotect_branch + + # Creates a repository branch. Requires Gitlab >= 6.8.x + # + # @example + # Gitlab.create_branch(3, 'api') + # Gitlab.repo_create_branch(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch The name of the new branch. + # @param [String] ref Create branch from commit sha or existing branch + # @return [Gitlab::ObjectifiedHash] + def create_branch(project, branch, ref) + post("/projects/#{url_encode project}/repository/branches", body: { branch_name: branch, ref: ref }) + end + alias_method :repo_create_branch, :create_branch + + # Deletes a repository branch. Requires Gitlab >= 6.8.x + # + # @example + # Gitlab.delete_branch(3, 'api') + # Gitlab.repo_delete_branch(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch The name of the branch to delete + # @return [Gitlab::ObjectifiedHash] + def delete_branch(project, branch) + delete("/projects/#{url_encode project}/repository/branches/#{branch}") + end + alias_method :repo_delete_branch, :delete_branch + end +end diff --git a/lib/gitlab/client/build_variables.rb b/lib/gitlab/client/build_variables.rb new file mode 100644 index 0000000..c07fa13 --- /dev/null +++ b/lib/gitlab/client/build_variables.rb @@ -0,0 +1,66 @@ +class Gitlab::Client + # Defines methods related to builds. + # @see https://docs.gitlab.com/ce/api/build_variables.html + module BuildVariables + # Gets a list of the project's build variables + # + # @example + # Gitlab.variables(5) + # + # @param [Integer, String] project The ID or name of a project. + # @return [Array] The list of variables. + def variables(project) + get("/projects/#{url_encode project}/variables") + end + + # Gets details of a project's specific build variable. + # + # @example + # Gitlab.build(5, "TEST_VARIABLE_1") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] key The key of a variable. + # @return [Gitlab::ObjectifiedHash] The variable. + def variable(project, key) + get("/projects/#{url_encode project}/variables/#{key}") + end + + # Create a build variable for a project. + # + # @example + # Gitlab.create_variable(5, "NEW_VARIABLE", "new value") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] key The key of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9` and `_` are allowed + # @param [String] value The value of a variable + # @return [Gitlab::ObjectifiedHash] The variable. + def create_variable(project, key, value) + post("/projects/#{url_encode project}/variables", body: { key: key, value: value }) + end + + # Update a project's build variable. + # + # @example + # Gitlab.create_variable(5, "NEW_VARIABLE", "updated value") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] key The key of a variable + # @param [String] value The value of a variable + # @return [Gitlab::ObjectifiedHash] The variable. + def update_variable(project, key, value) + put("/projects/#{url_encode project}/variables/#{key}", body: { value: value }) + end + + # Remove a project's build variable. + # + # @example + # Gitlab.remove_variable(5, "VARIABLE_1") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] key The key of a variable. + # @return [Gitlab::ObjectifiedHash] The variable. + def remove_variable(project, key) + delete("/projects/#{url_encode project}/variables/#{key}") + end + end +end diff --git a/lib/gitlab/client/builds.rb b/lib/gitlab/client/builds.rb new file mode 100644 index 0000000..2f75827 --- /dev/null +++ b/lib/gitlab/client/builds.rb @@ -0,0 +1,106 @@ +class Gitlab::Client + # Defines methods related to builds. + # @see https://docs.gitlab.com/ce/api/builds.html + module Builds + # Gets a list of project builds. + # + # @example + # Gitlab.builds(5) + # Gitlab.builds(5, { per_page: 10, page: 2 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @param [Integer, String] project The ID or name of a project. + # @return [Array] + def builds(project, options={}) + get("/projects/#{url_encode project}/builds", query: options) + end + + # Gets a single build. + # + # @example + # Gitlab.build(5, 36) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a build. + # @return [Gitlab::ObjectifiedHash] + def build(project, id) + get("/projects/#{url_encode project}/builds/#{id}") + end + + # Gets build artifacts. + # + # @example + # Gitlab.build_artifacts(1, 8) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a build. + # @return [Gitlab::FileResponse] + def build_artifacts(project, id) + get("/projects/#{url_encode project}/builds/#{id}/artifacts", + format: nil, + headers: { Accept: 'application/octet-stream' }, + parser: proc { |body, _| + if body.encoding == Encoding::ASCII_8BIT # binary response + ::Gitlab::FileResponse.new StringIO.new(body, 'rb+') + else # error with json response + ::Gitlab::Request.parse(body) + end + }) + end + + # Gets a list of builds for specific commit in a project. + # + # @example + # Gitlab.commit_builds(5, 'asdf') + # Gitlab.commit_builds(5, 'asdf', { per_page: 10, page: 2 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The SHA checksum of a commit. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] The list of builds. + def commit_builds(project, sha, options={}) + get("/projects/#{url_encode project}/repository/commits/#{sha}/builds", query: options) + end + + # Cancels a build. + # + # @example + # Gitlab.build_cancel(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a build. + # @return [Gitlab::ObjectifiedHash] The builds changes. + def build_cancel(project, id) + post("/projects/#{url_encode project}/builds/#{id}/cancel") + end + + # Retry a build. + # + # @example + # Gitlab.build_retry(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a build. + # @return [Array] The builds changes. + def build_retry(project, id) + post("/projects/#{url_encode project}/builds/#{id}/retry") + end + + # Erase a single build of a project (remove build artifacts and a build trace) + # + # @example + # Gitlab.build_erase(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a build. + # @return [Gitlab::ObjectifiedHash] The build's changes. + def build_erase(project, id) + post("/projects/#{url_encode project}/builds/#{id}/erase") + end + end +end diff --git a/lib/gitlab/client/commits.rb b/lib/gitlab/client/commits.rb new file mode 100644 index 0000000..97fba7c --- /dev/null +++ b/lib/gitlab/client/commits.rb @@ -0,0 +1,146 @@ +class Gitlab::Client + # Defines methods related to repository commits. + # @see https://docs.gitlab.com/ce/api/commits.html + module Commits + # Gets a list of project commits. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', { ref_name: 'api' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def commits(project, options={}) + get("/projects/#{url_encode project}/repository/commits", query: options) + end + alias_method :repo_commits, :commits + + # Gets a specific commit identified by the commit hash or name of a branch or tag. + # + # @example + # Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The commit hash or name of a repository branch or tag + # @return [Gitlab::ObjectifiedHash] + def commit(project, sha) + get("/projects/#{url_encode project}/repository/commits/#{sha}") + end + alias_method :repo_commit, :commit + + # Get the diff of a commit in a project. + # + # @example + # Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The name of a repository branch or tag or if not given the default branch. + # @return [Gitlab::ObjectifiedHash] + def commit_diff(project, sha) + get("/projects/#{url_encode project}/repository/commits/#{sha}/diff") + end + alias_method :repo_commit_diff, :commit_diff + + # Gets a list of comments for a commit. + # + # @example + # Gitlab.commit_comments(5, 'c9f9662a9b1116c838b523ed64c6abdb4aae4b8b') + # + # @param [Integer] project The ID of a project. + # @param [String] sha The commit hash or name of a repository branch or tag. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def commit_comments(project, commit, options={}) + get("/projects/#{url_encode project}/repository/commits/#{commit}/comments", query: options) + end + alias_method :repo_commit_comments, :commit_comments + + # Creates a new comment for a commit. + # + # @example + # Gitlab.create_commit_comment(5, 'c9f9662a9b1116c838b523ed64c6abdb4aae4b8b', 'Nice work on this commit!') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The commit hash or name of a repository branch or tag. + # @param [String] note The text of a comment. + # @param [Hash] options A customizable set of options. + # @option options [String] :path The file path. + # @option options [Integer] :line The line number. + # @option options [String] :line_type The line type (new or old). + # @return [Gitlab::ObjectifiedHash] Information about created comment. + def create_commit_comment(project, commit, note, options={}) + post("/projects/#{url_encode project}/repository/commits/#{commit}/comments", body: options.merge(note: note)) + end + alias_method :repo_create_commit_comment, :create_commit_comment + + # Get the status of a commit + # + # @example + # Gitlab.commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6', { name: 'jenkins' }) + # Gitlab.commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6', { name: 'jenkins', all: true }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The commit hash + # @param [Hash] options A customizable set of options. + # @option options [String] :ref Filter by ref name, it can be branch or tag + # @option options [String] :stage Filter by stage + # @option options [String] :name Filter by status name, eg. jenkins + # @option options [Boolean] :all The flag to return all statuses, not only latest ones + def commit_status(id, sha, options={}) + get("/projects/#{id}/repository/commits/#{sha}/statuses", query: options) + end + alias_method :repo_commit_status, :commit_status + + # Adds or updates a status of a commit. + # + # @example + # Gitlab.update_commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'success') + # Gitlab.update_commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'failed', { name: 'jenkins' }) + # Gitlab.update_commit_status(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'canceled', { name: 'jenkins', target_url: 'http://example.com/builds/1' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] sha The commit hash + # @param [String] state of the status. Can be: pending, running, success, failed, canceled + # @param [Hash] options A customizable set of options. + # @option options [String] :ref The ref (branch or tag) to which the status refers + # @option options [String] :name Filter by status name, eg. jenkins + # @option options [String] :target_url The target URL to associate with this status + def update_commit_status(id, sha, state, options={}) + post("/projects/#{id}/statuses/#{sha}", query: options.merge(state: state)) + end + alias_method :repo_update_commit_status, :update_commit_status + + # Creates a single commit with one or more changes + # + # @see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions + # Introduced in Gitlab 8.13 + # + # @example + # Gitlab.create_commit(2726132, 'master', 'refactors everything', [{action: 'create', file_path: '/foo.txt', content: 'bar'}]) + # Gitlab.create_commit(2726132, 'master', 'refactors everything', [{action: 'delete', file_path: '/foo.txt'}]) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] branch the branch name you wish to commit to + # @param [String] message the commit message + # @param [Array[Hash]] An array of action hashes to commit as a batch. See the next table for what attributes it can take. + # @option options [String] :author_email the email address of the author + # @option options [String] :author_name the name of the author + # @return [Gitlab::ObjectifiedHash] hash of commit related data + def create_commit(project, branch, message, actions, options={}) + payload = { + branch_name: branch, + commit_message: message, + actions: actions, + }.merge(options) + post("/projects/#{url_encode project}/repository/commits", query: payload) + end + end +end diff --git a/lib/gitlab/client/groups.rb b/lib/gitlab/client/groups.rb new file mode 100644 index 0000000..dc9459c --- /dev/null +++ b/lib/gitlab/client/groups.rb @@ -0,0 +1,144 @@ +class Gitlab::Client + # Defines methods related to groups. + # @see https://docs.gitlab.com/ce/api/groups.html + module Groups + # Gets a list of groups. + # + # @example + # Gitlab.groups + # Gitlab.groups({ per_page: 40, page: 2 }) + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def groups(options={}) + get("/groups", query: options) + end + + # Gets a single group. + # + # @example + # Gitlab.group(42) + # + # @param [Integer] id The ID of a group. + # @return [Gitlab::ObjectifiedHash] + def group(id) + get("/groups/#{id}") + end + + # Creates a new group. + # + # @example + # Gitlab.create_group('new-group', 'group-path') + # Gitlab.create_group('gitlab', 'gitlab-path', { description: 'New Gitlab project' }) + # + # @param [String] name The name of a group. + # @param [String] path The path of a group. + # @return [Gitlab::ObjectifiedHash] Information about created group. + def create_group(name, path, options={}) + body = { name: name, path: path }.merge(options) + post("/groups", body: body) + end + + # Delete's a group. + # + # @example + # Gitlab.delete_group(42) + # @param [Integer] id The ID of a group + # @return [Gitlab::ObjectifiedHash] Information about the deleted group. + def delete_group(id) + delete("/groups/#{id}") + end + + # Get a list of group members. + # + # @example + # Gitlab.group_members(1) + # Gitlab.group_members(1, { per_page: 40 }) + # + # @param [Integer] id The ID of a group. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def group_members(id, options={}) + get("/groups/#{id}/members", query: options) + end + + # Adds a user to group. + # + # @example + # Gitlab.add_group_member(1, 2, 40) + # + # @param [Integer] team_id The group id to add a member to. + # @param [Integer] user_id The user id of the user to add to the team. + # @param [Integer] access_level Project access level. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_group_member(team_id, user_id, access_level) + post("/groups/#{team_id}/members", body: { user_id: user_id, access_level: access_level }) + end + + # Edit a user of a group. + # + # @example + # Gitlab.edit_group_member(1, 2, 40) + # + # @param [Integer] team_id The group id of member to edit. + # @param [Integer] user_id The user id of the user to edit. + # @param [Integer] access_level Project access level. + # @return [Gitlab::ObjectifiedHash] Information about edited team member. + def edit_group_member(team_id, user_id, access_level) + put("/groups/#{team_id}/members/#{user_id}", body: { access_level: access_level }) + end + + # Removes user from user group. + # + # @example + # Gitlab.remove_group_member(1, 2) + # + # @param [Integer] team_id The group ID. + # @param [Integer] user_id The ID of a user. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_group_member(team_id, user_id) + delete("/groups/#{team_id}/members/#{user_id}") + end + + # Transfers a project to a group + # + # @example + # Gitlab.transfer_project_to_group(3, 50) + # + # @param [Integer] id The ID of a group. + # @param [Integer] project_id The ID of a project. + def transfer_project_to_group(id, project_id) + body = { id: id, project_id: project_id } + post("/groups/#{id}/projects/#{project_id}", body: body) + end + + # Search for groups by name + # + # @example + # Gitlab.group_search('gitlab') + # + # @param [String] search A string to search for in group names and paths. + # @param [Hash] options A customizable set of options. + # @option options [String] :per_page Number of projects to return per page + # @option options [String] :page The page to retrieve + # @return [Array] + def group_search(search, options={}) + options[:search] = search + get("/groups", query: options) + end + + # Get a list of projects under a group + # @example + # Gitlab.group_projects(1) + # + # @param [Integer] id The ID of a group + # @return [Array] List of projects under a group + def group_projects(id, options={}) + get("/groups/#{id}/projects", query: options) + end + end +end diff --git a/lib/gitlab/client/issues.rb b/lib/gitlab/client/issues.rb new file mode 100644 index 0000000..a039287 --- /dev/null +++ b/lib/gitlab/client/issues.rb @@ -0,0 +1,137 @@ +class Gitlab::Client + # Defines methods related to issues. + # @see https://docs.gitlab.com/ce/api/issues.html + module Issues + # Gets a list of user's issues. + # Will return a list of project's issues if project ID passed. + # + # @example + # Gitlab.issues + # Gitlab.issues(5) + # Gitlab.issues({ per_page: 40 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def issues(project=nil, options={}) + if project.to_s.empty? && project.to_i.zero? + get("/issues", query: options) + else + get("/projects/#{url_encode project}/issues", query: options) + end + end + + # Gets a single issue. + # + # @example + # Gitlab.issue(5, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] + def issue(project, id) + get("/projects/#{url_encode project}/issues/#{id}") + end + + # Creates a new issue. + # + # @example + # Gitlab.create_issue(5, 'New issue') + # Gitlab.create_issue(5, 'New issue', { description: 'This is a new issue', assignee_id: 42 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] title The title of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @return [Gitlab::ObjectifiedHash] Information about created issue. + def create_issue(project, title, options={}) + body = { title: title }.merge(options) + post("/projects/#{url_encode project}/issues", body: body) + end + + # Updates an issue. + # + # @example + # Gitlab.edit_issue(6, 1, { title: 'Updated title' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of an issue. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @option options [String] :state_event The state event of an issue ('close' or 'reopen'). + # @return [Gitlab::ObjectifiedHash] Information about updated issue. + def edit_issue(project, id, options={}) + put("/projects/#{url_encode project}/issues/#{id}", body: options) + end + + # Closes an issue. + # + # @example + # Gitlab.close_issue(3, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about closed issue. + def close_issue(project, id) + put("/projects/#{url_encode project}/issues/#{id}", body: { state_event: 'close' }) + end + + # Reopens an issue. + # + # @example + # Gitlab.reopen_issue(3, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about reopened issue. + def reopen_issue(project, id) + put("/projects/#{url_encode project}/issues/#{id}", body: { state_event: 'reopen' }) + end + + # Subscribe to an issue. + # + # @example + # Gitlab.subscribe_to_issue(3, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about subscribed issue. + def subscribe_to_issue(project, id) + post("/projects/#{url_encode project}/issues/#{id}/subscribe") + end + + # Unsubscribe from an issue. + # + # @example + # Gitlab.unsubscribe_from_issue(3, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about unsubscribed issue. + def unsubscribe_from_issue(project, id) + post("/projects/#{url_encode project}/issues/#{id}/unsubscribe") + end + + # Deletes an issue. + # Only for admins and project owners + # + # @example + # Gitlab.delete_issue(3, 42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about deleted issue. + def delete_issue(project, id) + delete("/projects/#{url_encode project}/issues/#{id}") + end + end +end diff --git a/lib/gitlab/client/jobs.rb b/lib/gitlab/client/jobs.rb new file mode 100644 index 0000000..68d6b36 --- /dev/null +++ b/lib/gitlab/client/jobs.rb @@ -0,0 +1,162 @@ +class Gitlab::Client + # Defines methods related to projects. + # @see https://docs.gitlab.com/ee/api/jobs.html + module Jobs + # Gets a list of Jobs for a Project + # + # @example + # Gitlab.jobs(1) + # Gitlab.jobs("project") + # + # @param [Integer, String] id The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Array] :scope The scope of jobs to show, one or array of: created, pending, running, failed, success, canceled, skipped, manual; showing all jobs if none provided. + # @return [Array] + def jobs(project_id, options = {}) + get("/projects/#{url_encode project_id}/jobs", query: options) + end + + # Gets a list of Jobs from a pipeline + # + # @example + # Gitlab.pipeline_jobs(1, 2) + # Gitlab.pipeline_jobs("project", 2) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the pipeline + # @param [Hash] options A customizable set of options. + # @option options [Array] :scope The scope of jobs to show, one or array of: created, pending, running, failed, success, canceled, skipped, manual; showing all jobs if none provided. + # @return [Array] + def pipeline_jobs(project_id, pipeline_id, options = {}) + get("/projects/#{url_encode project_id}/pipelines/#{pipeline_id}/jobs", query: options) + end + + # Gets a single job + # + # @example + # Gitlab.job(1, 2) + # Gitlab.job("project", 2) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + def job(project_id, job_id) + get("/projects/#{url_encode project_id}/jobs/#{job_id}") + end + + # Gets artifacts from a job + # + # @example + # Gitlab.job_artifacts(1, 2) + # Gitlab.job_artifacts("project", 2) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_artifacts(project_id, job_id) + get("/projects/#{url_encode project_id}/jobs/#{job_id}/artifacts", + format: nil, + headers: { Accept: 'text/plain' }, + parser: ::Gitlab::Request::Parser) + end + + # Download Job Artifact + # + # @example + # Gitlab.job_artifacts_download(1, "master", "release") + # Gitlab.job_artifacts_download("project", "master", "release") + # + # @param [Integer, String] id, The ID or name of a project. + # @param [String] ref, Ref Name + # @param [String] job, jobname + # @return [Array] + def job_artifacts_download(project_id, ref_name, job_name) + get("/projects/#{url_encode project_id}/jobs/artifacts/#{ref_name}/download", query: { job: job_name }, + format: nil, + headers: { Accept: 'text/plain' }, + parser: ::Gitlab::Request::Parser) + end + + # Get Job Trace + # + # @example + # Gitlab.job_trace(1,1) + # Gitlab.job_trace("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_trace(project_id, job_id) + get("/projects/#{url_encode project_id}/jobs/#{job_id}/trace", + format: nil, + headers: { Accept: 'text/plain' }, + parser: ::Gitlab::Request::Parser) + end + + # Cancel a job + # + # @example + # Gitlab.job_cancel(1,1) + # Gitlab.job_cancel("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_cancel(project_id, job_id) + post("/projects/#{url_encode project_id}/jobs/#{job_id}/cancel") + end + + # Retry a job + # + # @example + # Gitlab.job_retry(1,1) + # Gitlab.job_retry("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_retry(project_id, job_id) + post("/projects/#{url_encode project_id}/jobs/#{job_id}/retry") + end + + # Erase Job + # + # @example + # Gitlab.job_erase(1,1) + # Gitlab.job_erase("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_erase(project_id, job_id) + post("/projects/#{url_encode project_id}/jobs/#{job_id}/erase") + end + + # Play a Job + # Triggers a manual action to start a job. + # + # @example + # Gitlab.job_play(1,1) + # Gitlab.job_play("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_play(project_id, job_id) + post("/projects/#{url_encode project_id}/jobs/#{job_id}/play") + end + + # Keep Artifacts + # Prevents artifacts from being deleted when expiration is set. + # + # @example + # Gitlab.job_artifacts_keep(1,1) + # Gitlab.job_artifacts_keep("project", 1) + # + # @param [Integer, String] The ID or name of a project. + # @param [Integer] the id of the job + # @return [Array] + def job_artifacts_keep(project_id, job_id) + post("/projects/#{url_encode project_id}/jobs/#{job_id}/artifacts/keep") + end + end +end diff --git a/lib/gitlab/client/keys.rb b/lib/gitlab/client/keys.rb new file mode 100644 index 0000000..7d42a04 --- /dev/null +++ b/lib/gitlab/client/keys.rb @@ -0,0 +1,16 @@ +class Gitlab::Client + # Defines methods related to keys. + # @see https://docs.gitlab.com/ce/api/keys.html + module Keys + # Gets information about a key. + # + # @example + # Gitlab.key(1) + # + # @param [Integer] id The ID of a key. + # @return [Gitlab::ObjectifiedHash] + def key(id) + get("/keys/#{id}") + end + end +end diff --git a/lib/gitlab/client/labels.rb b/lib/gitlab/client/labels.rb new file mode 100644 index 0000000..97e2c27 --- /dev/null +++ b/lib/gitlab/client/labels.rb @@ -0,0 +1,57 @@ +class Gitlab::Client + # Defines methods related to labels. + # @see https://docs.gitlab.com/ce/api/labels.html + module Labels + # Gets a list of project's labels. + # + # @example + # Gitlab.labels(5) + # + # @param [Integer, String] project The ID or name of a project. + # @return [Array] + def labels(project) + get("/projects/#{url_encode project}/labels") + end + + # Creates a new label. + # + # @example + # Gitlab.create_label(42, "Backlog", '#DD10AA') + # + # @param [Integer, String] project The ID or name of a project. + # @option [String] name The name of a label. + # @option [String] color The color of a label. + # @return [Gitlab::ObjectifiedHash] Information about created label. + def create_label(project, name, color) + post("/projects/#{url_encode project}/labels", body: { name: name, color: color }) + end + + # Updates a label. + # + # @example + # Gitlab.edit_label(42, "Backlog", { new_name: 'TODO' }) + # Gitlab.edit_label(42, "Backlog", { new_name: 'TODO', color: '#DD10AA' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] name The name of a label. + # @param [Hash] options A customizable set of options. + # @option options [String] :new_name The new name of a label. + # @option options [String] :color The color of a label. + # @return [Gitlab::ObjectifiedHash] Information about updated label. + def edit_label(project, name, options={}) + put("/projects/#{url_encode project}/labels", body: options.merge(name: name)) + end + + # Deletes a label. + # + # @example + # Gitlab.delete_label(2, 'Backlog') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] name The name of a label. + # @return [Gitlab::ObjectifiedHash] Information about deleted label. + def delete_label(project, name) + delete("/projects/#{url_encode project}/labels", body: { name: name }) + end + end +end diff --git a/lib/gitlab/client/merge_requests.rb b/lib/gitlab/client/merge_requests.rb new file mode 100644 index 0000000..eea4cb9 --- /dev/null +++ b/lib/gitlab/client/merge_requests.rb @@ -0,0 +1,205 @@ +class Gitlab::Client + # Defines methods related to merge requests. + # @see https://docs.gitlab.com/ce/api/merge_requests.html + module MergeRequests + # Gets a list of project merge requests. + # + # @example + # Gitlab.merge_requests(5) + # Gitlab.merge_requests({ per_page: 40 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def merge_requests(project, options={}) + get("/projects/#{url_encode project}/merge_requests", query: options) + end + + # Gets a single merge request. + # + # @example + # Gitlab.merge_request(5, 36) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a merge request. + # @return ] The merge request's commits. + def merge_request_commits(project, id) + get("/projects/#{url_encode project}/merge_requests/#{id}/commits") + end + + # List issues that will close on merge + # + # @example + # Gitlab.merge_request_closes_issues(5, 1) + # + # @param [Integer] project The ID of a project + # @param [Integer] iid The internal ID of a merge request + def merge_request_closes_issues(project_id, merge_request_iid) + get("/projects/#{project_id}/merge_requests/#{merge_request_iid}/closes_issues") + end + + # Subscribes to a merge request. + # + # @example + # Gitlab.subscribe_to_merge_request(5, 1) + # Gitlab.subscribe_to_merge_request('gitlab', 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a merge request. + # @return [Gitlab::ObjectifiedHash] Information about subscribed merge request. + def subscribe_to_merge_request(project, id) + post("/projects/#{url_encode project}/merge_requests/#{id}/subscribe") + end + + # Unsubscribes from a merge request. + # + # @example + # Gitlab.unsubscribe_from_merge_request(5, 1) + # Gitlab.unsubscribe_from_merge_request('gitlab', 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a merge request. + # @return [Gitlab::ObjectifiedHash] Information about unsubscribed merge request. + def unsubscribe_from_merge_request(project, id) + post("/projects/#{url_encode project}/merge_requests/#{id}/unsubscribe") + end + end +end diff --git a/lib/gitlab/client/milestones.rb b/lib/gitlab/client/milestones.rb new file mode 100644 index 0000000..ab8a4dd --- /dev/null +++ b/lib/gitlab/client/milestones.rb @@ -0,0 +1,92 @@ +class Gitlab::Client + # Defines methods related to milestones. + # @see https://docs.gitlab.com/ce/api/milestones.html + module Milestones + # Gets a list of project's milestones. + # + # @example + # Gitlab.milestones(5) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def milestones(project, options={}) + get("/projects/#{url_encode project}/milestones", query: options) + end + + # Gets a single milestone. + # + # @example + # Gitlab.milestone(5, 36) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a milestone. + # @return [Gitlab::ObjectifiedHash] + def milestone(project, id) + get("/projects/#{url_encode project}/milestones/#{id}") + end + + # Gets the issues of a given milestone. + # + # @example + # Gitlab.milestone_issues(5, 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer, String] milestone The ID of a milestone. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def milestone_issues(project, milestone, options={}) + get("/projects/#{url_encode project}/milestones/#{milestone}/issues", query: options) + end + + # Gets the merge_requests of a given milestone. + # + # @example + # Gitlab.milestone_merge_requests(5, 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer, String] milestone The ID of a milestone. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def milestone_merge_requests(project, milestone, options={}) + get("/projects/#{url_encode project}/milestones/#{milestone}/merge_requests", query: options) + end + + # Creates a new milestone. + # + # @example + # Gitlab.create_milestone(5, 'v1.0') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] title The title of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @return [Gitlab::ObjectifiedHash] Information about created milestone. + def create_milestone(project, title, options={}) + body = { title: title }.merge(options) + post("/projects/#{url_encode project}/milestones", body: body) + end + + # Updates a milestone. + # + # @example + # Gitlab.edit_milestone(5, 2, { state_event: 'activate' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a milestone. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @option options [String] :state_event The state of a milestone ('close' or 'activate'). + # @return [Gitlab::ObjectifiedHash] Information about updated milestone. + def edit_milestone(project, id, options={}) + put("/projects/#{url_encode project}/milestones/#{id}", body: options) + end + end +end diff --git a/lib/gitlab/client/namespaces.rb b/lib/gitlab/client/namespaces.rb new file mode 100644 index 0000000..1979ce6 --- /dev/null +++ b/lib/gitlab/client/namespaces.rb @@ -0,0 +1,20 @@ +class Gitlab::Client + # Defines methods related to namespaces + # @see https://docs.gitlab.com/ce/api/namespaces.html + module Namespaces + # Gets a list of namespaces. + # @see https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces + # + # @example + # Gitlab.namespaces + # + # @param [Hash] options A customizable set of options. + # @options options [Integer] :page The page number. + # @options options [Integer] :per_page The number of results per page. + # @options opttion [String] :search The string to search for. + # @return [Array] + def namespaces(options={}) + get("/namespaces", query: options) + end + end +end diff --git a/lib/gitlab/client/notes.rb b/lib/gitlab/client/notes.rb new file mode 100644 index 0000000..495d372 --- /dev/null +++ b/lib/gitlab/client/notes.rb @@ -0,0 +1,161 @@ +class Gitlab::Client + # Defines methods related to notes. + # @see https://docs.gitlab.com/ce/api/notes.html + module Notes + # Gets a list of projects notes. + # + # @example + # Gitlab.notes(5) + # + # @param [Integer] project The ID of a project. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def notes(project, options={}) + get("/projects/#{url_encode project}/notes", query: options) + end + + # Gets a list of notes for a issue. + # + # @example + # Gitlab.issue_notes(5, 10) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def issue_notes(project, issue, options={}) + get("/projects/#{url_encode project}/issues/#{issue}/notes", query: options) + end + + # Gets a list of notes for a snippet. + # + # @example + # Gitlab.snippet_notes(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def snippet_notes(project, snippet, options={}) + get("/projects/#{url_encode project}/snippets/#{snippet}/notes", query: options) + end + + # Gets a list of notes for a merge request. + # + # @example + # Gitlab.merge_request_notes(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] merge_request The ID of a merge request. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def merge_request_notes(project, merge_request, options={}) + get("/projects/#{url_encode project}/merge_requests/#{merge_request}/notes", query: options) + end + + # Gets a single wall note. + # + # @example + # Gitlab.note(5, 15) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def note(project, id) + get("/projects/#{url_encode project}/notes/#{id}") + end + + # Gets a single issue note. + # + # @example + # Gitlab.issue_note(5, 10, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def issue_note(project, issue, id) + get("/projects/#{url_encode project}/issues/#{issue}/notes/#{id}") + end + + # Gets a single snippet note. + # + # @example + # Gitlab.snippet_note(5, 11, 3) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def snippet_note(project, snippet, id) + get("/projects/#{url_encode project}/snippets/#{snippet}/notes/#{id}") + end + + # Gets a single merge_request note. + # + # @example + # Gitlab.merge_request_note(5, 11, 3) + # + # @param [Integer] project The ID of a project. + # @param [Integer] merge_request The ID of a merge_request. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def merge_request_note(project, merge_request, id) + get("/projects/#{url_encode project}/merge_requests/#{merge_request}/notes/#{id}") + end + + # Creates a new wall note. + # + # @example + # Gitlab.create_note(5, 'This is a wall note!') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_note(project, body) + post("/projects/#{url_encode project}/notes", body: { body: body }) + end + + # Creates a new issue note. + # + # @example + # Gitlab.create_issue_note(6, 1, 'Adding a note to my issue.') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] issue The ID of an issue. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_issue_note(project, issue, body) + post("/projects/#{url_encode project}/issues/#{issue}/notes", body: { body: body }) + end + + # Creates a new snippet note. + # + # @example + # Gitlab.create_snippet_note(3, 2, 'Look at this awesome snippet!') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_snippet_note(project, snippet, body) + post("/projects/#{url_encode project}/snippets/#{snippet}/notes", body: { body: body }) + end + + # Creates a new note for a single merge request. + # + # @example + # Gitlab.create_merge_request_note(5, 3, 'This MR is ready for review.') + # + # @param [Integer] project The ID of a project. + # @param [Integer] merge_request The ID of a merge request. + # @param [String] body The content of a note. + def create_merge_request_note(project, merge_request, body) + post("/projects/#{url_encode project}/merge_requests/#{merge_request}/notes", body: { body: body }) + end + end +end diff --git a/lib/gitlab/client/pipeline_triggers.rb b/lib/gitlab/client/pipeline_triggers.rb new file mode 100644 index 0000000..ce347de --- /dev/null +++ b/lib/gitlab/client/pipeline_triggers.rb @@ -0,0 +1,101 @@ +class Gitlab::Client + # Defines methods related to pipelines. + # @see https://docs.gitlab.com/ce/api/pipeline_triggers.html + # @see https://docs.gitlab.com/ce/ci/triggers/README.html + module PipelineTriggers + # Gets a list of the project's pipeline triggers + # + # @example + # Gitlab.triggers(5) + # + # @param [Integer, String] project The ID or name of a project. + # @return [Array] The list of triggers. + def triggers(project) + get("/projects/#{url_encode project}/triggers") + end + + # Gets details of project's pipeline trigger. + # + # @example + # Gitlab.trigger(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] trigger_id The trigger ID. + # @return [Gitlab::ObjectifiedHash] The trigger. + def trigger(project, trigger_id) + get("/projects/#{url_encode project}/triggers/#{trigger_id}") + end + + # Create a pipeline trigger for a project. + # + # @example + # Gitlab.create_trigger(5, description: "my description") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] description The trigger name + # @return [Gitlab::ObjectifiedHash] The created trigger. + def create_trigger(project, description) + post("/projects/#{url_encode project}/triggers", body: {description: description}) + end + + # Update a project trigger + # + # @example + # Gitlab.update_trigger(5, 1, description: "my description") + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] trigger_id The trigger ID. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The trigger name. + # @return [Gitlab::ObjectifiedHash] The updated trigger. + def update_trigger(project, trigger_id, options={}) + put("/projects/#{url_encode project}/triggers/#{trigger_id}", body: options) + end + + # Take ownership of a project trigger + # + # @example + # Gitlab.trigger_take_ownership(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] trigger_id The trigger ID. + # @return [Gitlab::ObjectifiedHash] The updated trigger. + def trigger_take_ownership(project, trigger_id) + post("/projects/#{url_encode project}/triggers/#{trigger_id}/take_ownership") + end + + # Remove a project's pipeline trigger. + # + # @example + # Gitlab.remove_trigger(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] trigger_id The trigger ID. + # @return [void] This API call returns an empty response body. + def remove_trigger(project, trigger_id) + delete("/projects/#{url_encode project}/triggers/#{trigger_id}") + end + alias_method :delete_trigger, :remove_trigger + + # Run the given project pipeline trigger. + # + # @example + # Gitlab.trigger_build(5, '7b9148c158980bbd9bcea92c17522d', 'master') + # Gitlab.trigger_build(5, '7b9148c158980bbd9bcea92c17522d', 'master', { variable1: "value", variable2: "value2" }) + # + # @see https://docs.gitlab.com/ce/ci/triggers/README.html + # + # @param [Integer, String] project The ID or name of the project. + # @param [String] token The token of a trigger. + # @param [String] ref Branch or tag name to build. + # @param [Hash] variables A set of build variables to use for the build. (optional) + # @return [Gitlab::ObjectifiedHash] The trigger. + def run_trigger(project, token, ref, variables={}) + post("/projects/#{url_encode project}/trigger/pipeline", unauthenticated: true, body: { + token: token, + ref: ref, + variables: variables + }) + end + end +end diff --git a/lib/gitlab/client/pipelines.rb b/lib/gitlab/client/pipelines.rb new file mode 100644 index 0000000..fb140f3 --- /dev/null +++ b/lib/gitlab/client/pipelines.rb @@ -0,0 +1,68 @@ +class Gitlab::Client + # Defines methods related to pipelines. + # @see https://docs.gitlab.com/ce/api/pipelines.html + module Pipelines + # Gets a list of project pipelines. + # + # @example + # Gitlab.pipelines(5) + # Gitlab.pipelines(5, { per_page: 10, page: 2 }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def pipelines(project, options={}) + get("/projects/#{url_encode project}/pipelines", query: options) + end + + # Gets a single pipeline. + # + # @example + # Gitlab.pipeline(5, 36) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a pipeline. + # @return [Gitlab::ObjectifiedHash] + def pipeline(project, id) + get("/projects/#{url_encode project}/pipelines/#{id}") + end + + # Create a pipeline. + # + # @example + # Gitlab.create_pipeline(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] ref Reference to commit. + # @return [Gitlab::ObjectifiedHash] The pipelines changes. + def create_pipeline(project, ref) + post("/projects/#{url_encode project}/pipeline?ref=#{ref}") + end + + # Cancels a pipeline. + # + # @example + # Gitlab.cancel_pipeline(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a pipeline. + # @return [Gitlab::ObjectifiedHash] The pipelines changes. + def cancel_pipeline(project, id) + post("/projects/#{url_encode project}/pipelines/#{id}/cancel") + end + + # Retry a pipeline. + # + # @example + # Gitlab.retry_pipeline(5, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a pipeline. + # @return [Array] The pipelines changes. + def retry_pipeline(project, id) + post("/projects/#{url_encode project}/pipelines/#{id}/retry") + end + end +end diff --git a/lib/gitlab/client/projects.rb b/lib/gitlab/client/projects.rb new file mode 100644 index 0000000..69b3bd5 --- /dev/null +++ b/lib/gitlab/client/projects.rb @@ -0,0 +1,471 @@ +class Gitlab::Client + # Defines methods related to projects. + # @see https://docs.gitlab.com/ce/api/projects.html + module Projects + # Gets a list of projects owned by the authenticated user. + # + # @example + # Gitlab.projects + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only) + # @return [Array] + def projects(options={}) + if options[:scope] + get("/projects/#{options[:scope]}", query: options) + else + get("/projects", query: options) + end + end + + # Search for projects by name. + # + # @example + # Gitlab.project_search('gitlab') + # Gitlab.project_search('gitlab', { order_by: 'last_activity_at' }) + # Gitlab.search_projects('gitlab', { order_by: 'name', sort: 'asc' }) + # + # @param [Hash] options A customizable set of options. + # @option options [String] :per_page Number of projects to return per page + # @option options [String] :page The page to retrieve + # @option options [String] :order_by Return requests ordered by id, name, created_at or last_activity_at fields + # @option options [String] :sort Return requests sorted in asc or desc order + # @return [Array] + def project_search(query, options={}) + get("/projects/search/#{query}", query: options) + end + alias_method :search_projects, :project_search + + # Gets information about a project. + # + # @example + # Gitlab.project(3) + # Gitlab.project('gitlab') + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] + def project(id) + get("/projects/#{url_encode id}") + end + + # Gets a list of project events. + # + # @example + # Gitlab.project_events(42) + # Gitlab.project_events('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_events(project, options={}) + get("/projects/#{url_encode project}/events", query: options) + end + + # Creates a new project. + # + # @example + # Gitlab.create_project('gitlab') + # Gitlab.create_project('viking', { description: 'Awesome project' }) + # Gitlab.create_project('Red', { wall_enabled: false }) + # + # @param [String] name The name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a project. + # @option options [String] :default_branch The default branch of a project. + # @option options [String] :namespace_id The namespace in which to create a project. + # @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true). + # @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true). + # @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true). + # @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true). + # @option options [Integer] :user_id The user/owner id of a project. + # @return [Gitlab::ObjectifiedHash] Information about created project. + def create_project(name, options={}) + url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects" + post(url, body: { name: name }.merge(options)) + end + + # Deletes a project. + # + # @example + # Gitlab.delete_project(4) + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] Information about deleted project. + def delete_project(id) + delete("/projects/#{id}") + end + + # Gets a list of project team members. + # + # @example + # Gitlab.team_members(42) + # Gitlab.team_members('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :query The search query. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def team_members(project, options={}) + get("/projects/#{url_encode project}/members", query: options) + end + + # Gets a project team member. + # + # @example + # Gitlab.team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a project team member. + # @return [Gitlab::ObjectifiedHash] + def team_member(project, id) + get("/projects/#{url_encode project}/members/#{id}") + end + + # Adds a user to project team. + # + # @example + # Gitlab.add_team_member('gitlab', 2, 40) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_team_member(project, id, access_level) + post("/projects/#{url_encode project}/members", body: { user_id: id, access_level: access_level }) + end + + # Updates a team member's project access level. + # + # @example + # Gitlab.edit_team_member('gitlab', 3, 20) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Array] Information about updated team member. + def edit_team_member(project, id, access_level) + put("/projects/#{url_encode project}/members/#{id}", body: { access_level: access_level }) + end + + # Removes a user from project team. + # + # @example + # Gitlab.remove_team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_team_member(project, id) + delete("/projects/#{url_encode project}/members/#{id}") + end + + # Gets a list of project hooks. + # + # @example + # Gitlab.project_hooks(42) + # Gitlab.project_hooks('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_hooks(project, options={}) + get("/projects/#{url_encode project}/hooks", query: options) + end + + # Gets a project hook. + # + # @example + # Gitlab.project_hook(42, 5) + # Gitlab.project_hook('gitlab', 5) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a hook. + # @return [Gitlab::ObjectifiedHash] + def project_hook(project, id) + get("/projects/#{url_encode project}/hooks/#{id}") + end + + # Adds a new hook to the project. + # + # @example + # Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] url The hook URL. + # @param [Hash] options A customizable set of options. + # @param option [Boolean] :push_events Trigger hook on push events (0 = false, 1 = true) + # @param option [Boolean] :issues_events Trigger hook on issues events (0 = false, 1 = true) + # @param option [Boolean] :merge_requests_events Trigger hook on merge_requests events (0 = false, 1 = true) + # @param option [Boolean] :tag_push_events Trigger hook on push_tag events (0 = false, 1 = true) + # @return [Gitlab::ObjectifiedHash] Information about added hook. + def add_project_hook(project, url, options={}) + body = { url: url }.merge(options) + post("/projects/#{url_encode project}/hooks", body: body) + end + + # Updates a project hook URL. + # + # @example + # Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the hook. + # @param [String] url The hook URL. + # @param [Hash] options A customizable set of options. + # @param option [Boolean] :push_events Trigger hook on push events (0 = false, 1 = true) + # @param option [Boolean] :issues_events Trigger hook on issues events (0 = false, 1 = true) + # @param option [Boolean] :merge_requests_events Trigger hook on merge_requests events (0 = false, 1 = true) + # @param option [Boolean] :tag_push_events Trigger hook on push_tag events (0 = false, 1 = true) + # @return [Gitlab::ObjectifiedHash] Information about updated hook. + def edit_project_hook(project, id, url, options={}) + body = { url: url }.merge(options) + put("/projects/#{url_encode project}/hooks/#{id}", body: body) + end + + # Deletes a hook from project. + # + # @example + # Gitlab.delete_project_hook('gitlab', 4) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] id The ID of the hook. + # @return [Gitlab::ObjectifiedHash] Information about deleted hook. + def delete_project_hook(project, id) + delete("/projects/#{url_encode project}/hooks/#{id}") + end + + # Gets a project push rule. + # @see https://docs.gitlab.com/ee/api/projects.html#show-project-push-rules + # + # @example + # Gitlab.push_rule(42) + # + # @param [Integer] id The ID of a project. + # @return [Gitlab::ObjectifiedHash] + def push_rule(id) + get("/projects/#{id}/push_rule") + end + + # Adds a project push rule. + # @see https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule + # + # @example + # Gitlab.add_push_rule(42, { deny_delete_tag: false, commit_message_regex: '\\b[A-Z]{3}-[0-9]+\\b' }) + # + # @param [Integer] id The ID of a project. + # @param [Hash] options A customizable set of options. + # @param option [Boolean] :deny_delete_tag Do not allow users to remove git tags with git push (0 = false, 1 = true) + # @param option [String] :commit_message_regex Commit message regex + # @return [Gitlab::ObjectifiedHash] Information about added push rule. + def add_push_rule(id, options={}) + post("/projects/#{id}/push_rule", body: options) + end + + # Updates a project push rule. + # @see https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule + # + # @example + # Gitlab.edit_push_rule(42, { deny_delete_tag: false, commit_message_regex: '\\b[A-Z]{3}-[0-9]+\\b' }) + # + # @param [Integer] id The ID of a project. + # @param [Hash] options A customizable set of options. + # @param option [Boolean] :deny_delete_tag Do not allow users to remove git tags with git push (0 = false, 1 = true) + # @param option [String] :commit_message_regex Commit message regex + # @return [Gitlab::ObjectifiedHash] Information about updated push rule. + def edit_push_rule(id, options={}) + put("/projects/#{id}/push_rule", body: options) + end + + # Deletes a push rule from a project. + # @see https://docs.gitlab.com/ee/api/projects.html#delete-project-push-rule + # + # @example + # Gitlab.delete_push_rule(42) + # + # @param [Integer] id The ID of a project. + # @return [Gitlab::ObjectifiedHash] Information about deleted push rule. + def delete_push_rule(id, options={}) + delete("/projects/#{id}/push_rule") + end + + # Mark this project as forked from the other + # + # @example + # Gitlab.make_forked(42, 24) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the project it is forked from. + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def make_forked_from(project, id) + post("/projects/#{url_encode project}/fork/#{id}") + end + + # Remove a forked_from relationship for a project. + # + # @example + # Gitlab.remove_forked(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] project The ID of the project it is forked from + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def remove_forked(project) + delete("/projects/#{url_encode project}/fork") + end + + # Gets a project deploy keys. + # + # @example + # Gitlab.deploy_keys(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def deploy_keys(project, options={}) + get("/projects/#{url_encode project}/deploy_keys", query: options) + end + + # Gets a single project deploy key. + # + # @example + # Gitlab.deploy_key(42, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] + def deploy_key(project, id) + get("/projects/#{url_encode project}/deploy_keys/#{id}") + end + + # Creates a new deploy key. + # + # @example + # Gitlab.create_deploy_key(42, 'My Key', 'Key contents') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] title The title of a deploy key. + # @param [String] key The content of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about created deploy key. + def create_deploy_key(project, title, key) + post("/projects/#{url_encode project}/deploy_keys", body: { title: title, key: key }) + end + + # Enables a deploy key at the project. + # + # @example + # Gitlab.enable_deploy_key(42, 66) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] key The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about the enabled deploy key. + def enable_deploy_key(project, key) + post("/projects/#{url_encode project}/deploy_keys/#{key}/enable", body: { id: project, key_id: key }) + end + + # Disables a deploy key at the project. + # + # @example + # Gitlab.disable_deploy_key(42, 66) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] key The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about the disabled deploy key. + def disable_deploy_key(project, key) + post("/projects/#{url_encode project}/deploy_keys/#{key}/disable", body: { id: project, key_id: key }) + end + + # Deletes a deploy key from project. + # + # @example + # Gitlab.delete_deploy_key(42, 1) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about deleted deploy key. + def delete_deploy_key(project, id) + delete("/projects/#{url_encode project}/deploy_keys/#{id}") + end + + # Forks a project into the user namespace. + # + # @example + # Gitlab.create_fork(42) + # Gitlab.create_fork(42, { sudo: 'another_username' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :sudo The username the project will be forked for + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def create_fork(id, options={}) + post("/projects/#{id}/fork", body: options) + end + + # Updates an existing project. + # + # @example + # Gitlab.edit_project(42) + # Gitlab.edit_project(42, { name: 'project_name' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :name The name of a project + # @option options [String] :path The name of a project + # @option options [String] :description The name of a project + # @return [Gitlab::ObjectifiedHash] Information about the edited project. + def edit_project(id, options={}) + put("/projects/#{id}", query: options) + end + + # Share project with group. + # + # @example + # Gitlab.share_project_with_group('gitlab', 2, 40) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a group. + # @param [Integer] group_access The access level to project. + def share_project_with_group(project, id, group_access) + post("/projects/#{url_encode project}/share", body: { group_id: id, group_access: group_access }) + end + + # Stars a project. + # @see https://docs.gitlab.com/ce/api/projects.html#star-a-project + # + # @example + # Gitlab.star_project(42) + # Gitlab.star_project('gitlab-org/gitlab-ce') + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] Information about starred project. + def star_project(id) + post("/projects/#{id}/star") + end + + # Unstars a project. + # @see https://docs.gitlab.com/ce/api/projects.html#unstar-a-project + # + # @example + # Gitlab.unstar_project(42) + # Gitlab.unstar_project('gitlab-org/gitlab-ce') + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] Information about unstarred project. + def unstar_project(id) + delete("/projects/#{id}/star") + end + end +end diff --git a/lib/gitlab/client/repositories.rb b/lib/gitlab/client/repositories.rb new file mode 100644 index 0000000..f169105 --- /dev/null +++ b/lib/gitlab/client/repositories.rb @@ -0,0 +1,59 @@ +class Gitlab::Client + # Defines methods related to repositories. + # @see https://docs.gitlab.com/ce/api/repositories.html + module Repositories + # Get file tree project (root level). + # + # @example + # Gitlab.tree(42) + # Gitlab.tree(42, { path: 'Gemfile' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :path The path inside repository. + # @option options [String] :ref_name The name of a repository branch or tag. + # @return [Gitlab::ObjectifiedHash] + def tree(project, options={}) + get("/projects/#{url_encode project}/repository/tree", query: options) + end + alias_method :repo_tree, :tree + + # Get project repository archive + # + # @example + # Gitlab.repo_archive(42) + # Gitlab.repo_archive(42, 'deadbeef') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] ref The commit sha, branch, or tag to download. + # @return [Gitlab::FileResponse] + def repo_archive(project, ref = 'master') + get("/projects/#{url_encode project}/repository/archive", + format: nil, + headers: { Accept: 'application/octet-stream' }, + query: { sha: ref }, + parser: proc { |body, _| + if body.encoding == Encoding::ASCII_8BIT # binary response + ::Gitlab::FileResponse.new StringIO.new(body, 'rb+') + else # error with json response + ::Gitlab::Request.parse(body) + end + }) + end + + # Compares branches, tags or commits. + # + # @example + # Gitlab.compare(42, 'master', 'feature/branch') + # Gitlab.repo_compare(42, 'master', 'feature/branch') + # + # @param [Integer] project The ID of a project. + # @param [String] from The commit SHA or branch name of from branch. + # @param [String] to The commit SHA or branch name of to branch. + # @return [Gitlab::ObjectifiedHash] + def compare(project, from, to) + get("/projects/#{url_encode project}/repository/compare", query: { from: from, to: to }) + end + alias_method :repo_compare, :compare + end +end diff --git a/lib/gitlab/client/repository_files.rb b/lib/gitlab/client/repository_files.rb new file mode 100644 index 0000000..983f58d --- /dev/null +++ b/lib/gitlab/client/repository_files.rb @@ -0,0 +1,107 @@ +require 'base64' + +class Gitlab::Client + # Defines methods related to repository files. + # @see https://docs.gitlab.com/ce/api/repository_files.html + module RepositoryFiles + # Get the contents of a file + # + # @example + # Gitlab.file_contents(42, 'Gemfile') + # Gitlab.repo_file_contents(3, 'Gemfile', 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] filepath The relative path of the file in the repository + # @param [String] ref The name of a repository branch or tag or if not given the default branch. + # @return [String] + def file_contents(project, filepath, ref='master') + ref = URI.encode(ref, /\W/) + get "/projects/#{url_encode project}/repository/files/#{url_encode filepath}/raw", + query: { ref: ref}, + format: nil, + headers: { Accept: 'text/plain' }, + parser: ::Gitlab::Request::Parser + end + alias_method :repo_file_contents, :file_contents + + # Gets a repository file. + # + # @example + # Gitlab.get_file(42, "README.md", "master") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] file_path The full path of the file. + # @param [String] ref The name of branch, tag or commit. + # @return [Gitlab::ObjectifiedHash] + def get_file(project, file_path, ref) + get("/projects/#{url_encode project}/repository/files/#{url_encode file_path}", query: { + ref: ref + }) + end + + # Creates a new repository file. + # + # @example + # Gitlab.create_file(42, "path", "branch", "content", "commit message") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] full path to new file. + # @param [String] the name of the branch. + # @param [String] file content. + # @param [String] commit message. + # @return [Gitlab::ObjectifiedHash] + def create_file(project, path, branch, content, commit_message) + post("/projects/#{url_encode project}/repository/files", body: { + file_path: path, + branch_name: branch, + commit_message: commit_message + }.merge(encoded_content_attributes(content))) + end + + # Edits an existing repository file. + # + # @example + # Gitlab.edit_file(42, "path", "branch", "content", "commit message") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] full path to new file. + # @param [String] the name of the branch. + # @param [String] file content. + # @param [String] commit message. + # @return [Gitlab::ObjectifiedHash] + def edit_file(project, path, branch, content, commit_message) + put("/projects/#{url_encode project}/repository/files", body: { + file_path: path, + branch_name: branch, + commit_message: commit_message + }.merge(encoded_content_attributes(content))) + end + + # Removes an existing repository file. + # + # @example + # Gitlab.remove_file(42, "path", "branch", "commit message") + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] full path to new file. + # @param [String] the name of the branch. + # @param [String] commit message. + # @return [Gitlab::ObjectifiedHash] + def remove_file(project, path, branch, commit_message) + delete("/projects/#{url_encode project}/repository/files", body: { + file_path: path, + branch_name: branch, + commit_message: commit_message + }) + end + + private + + def encoded_content_attributes(content) + { + encoding: 'base64', + content: Base64.encode64(content) + } + end + end +end diff --git a/lib/gitlab/client/runners.rb b/lib/gitlab/client/runners.rb new file mode 100644 index 0000000..5e3b46e --- /dev/null +++ b/lib/gitlab/client/runners.rb @@ -0,0 +1,115 @@ +class Gitlab::Client + # Defines methods related to runners. + # @see https://docs.gitlab.com/ce/api/runners.html + module Runners + + # Get a list of specific runners available to the user. + # @see https://docs.gitlab.com/ce/api/runners.html#list-owned-runners + # + # @example + # Gitlab.runners + # Gitlab.runners(:active) + # Gitlab.runners(:paused) + # + # @param [Hash] options A customizable set of options. + # @option options [String] :scope The scope of specific runners to show, one of: active, paused, online; showing all runners if none provided + # @return [Array] + def runners(options = {}) + get("/runners", query: options) + end + + # Get a list of all runners in the GitLab instance (specific and shared). Access is restricted to users with admin privileges. + # @see https://docs.gitlab.com/ce/api/runners.html#list-all-runners + # + # @example + # Gitlab.all_runners + # + # @param [Hash] options A customizable set of options. + # @option options [String] :scope The scope of runners to show, one of: specific, shared, active, paused, online; showing all runners if none provided + # @return [Array] + def all_runners(options = {}) + get("/runners/all", query: options) + end + + # Get details of a runner.. + # @see https://docs.gitlab.com/ce/api/runners.html#get-runners-details + # + # @example + # Gitlab.runner(42) + # + # @param [Integer, String] id The ID of a runner + # @return + def runner(id) + get("/runners/#{id}") + end + + # Update details of a runner. + # @see https://docs.gitlab.com/ce/api/runners.html#update-runners-details + # + # @example + # Gitlab.update_runner(42, { description: 'Awesome runner' }) + # Gitlab.update_runner(42, { active: false }) + # Gitlab.update_runner(42, { tag_list: [ 'awesome', 'runner' ] }) + # + # @param [Integer, String] id The ID of a runner + # @param [Hash] options A customizable set of options. + # @option options [String] :active The state of a runner; can be set to true or false. + # @option options [String] :tag_list The list of tags for a runner; put array of tags, that should be finally assigned to a runner + # @return + def update_runner(id, options={}) + put("/runners/#{id}", query: options) + end + + # Remove a runner. + # @see https://docs.gitlab.com/ce/api/runners.html#remove-a-runner + # + # @example + # Gitlab.delete_runner(42) + # + # @param [Integer, String] id The ID of a runner + # @return + def delete_runner(id) + delete("/runners/#{id}") + end + + # List all runners (specific and shared) available in the project. Shared runners are listed if at least one shared runner is defined and shared runners usage is enabled in the project's settings. + # @see https://docs.gitlab.com/ce/api/runners.html#list-projects-runners + # + # @example + # Gitlab.project_runners(42) + # + # @param [Integer, String] id The ID or name of a project. + # @return [Array] + def project_runners(project_id) + get("/projects/#{url_encode project_id}/runners") + end + + # Enable an available specific runner in the project. + # @see https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project + # + # @example + # Gitlab.project_enable_runner(2, 42) + # + # @param [Integer, String] id The ID or name of a project. + # @param [Integer, String] id The ID of a runner. + # @return + def project_enable_runner(project_id, id) + body = { runner_id: id } + post("/projects/#{url_encode project_id}/runners", body: body) + end + + # Disable a specific runner from the project. It works only if the project isn't the only project associated with the specified runner. + # @see https://docs.gitlab.com/ce/api/runners.html#disable-a-runner-from-project + # + # @example + # Gitlab.project_disable_runner(2, 42) + # + # @param [Integer, String] id The ID or name of a project. + # @param [Integer, String] runner_id The ID of a runner. + # @return + def project_disable_runner(id, runner_id) + delete("/projects/#{url_encode id}/runners/#{runner_id}") + end + + end +end diff --git a/lib/gitlab/client/services.rb b/lib/gitlab/client/services.rb new file mode 100644 index 0000000..81bf940 --- /dev/null +++ b/lib/gitlab/client/services.rb @@ -0,0 +1,50 @@ +class Gitlab::Client + # Third party services connected to a project. + # @see https://docs.gitlab.com/ce/api/services.html + module Services + # Create/Edit service + # Full service params documentation: https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/services.md + # + # @example + # Gitlab.change_service(42, :redmine, { new_issue_url: 'https://example.com/projects/test_project/issues/new', + # project_url: 'https://example.com/projects/test_project/issues', + # issues_url: 'https://example.com/issues/:id' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] service A service code name. + # @param [Hash] params A service parameters. + # @return [Boolean] + def change_service(project, service, params) + put("/projects/#{url_encode project}/services/#{correct_service_name(service)}", body: params) + end + + # Delete service + # + # @example + # Gitlab.delete_service(42, :redmine) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] service A service code name. + # @return [Boolean] + def delete_service(project, service) + delete("/projects/#{url_encode project}/services/#{correct_service_name(service)}") + end + + # Get service + # + # @example + # Gitlab.service(42, :redmine) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] service A service code name. + # @return [Gitlab::ObjectifiedHash] + def service(project, service) + get("/projects/#{url_encode project}/services/#{correct_service_name(service)}") + end + + private + def correct_service_name(service) + service.to_s.gsub('_', '-') + end + end +end diff --git a/lib/gitlab/client/snippets.rb b/lib/gitlab/client/snippets.rb new file mode 100644 index 0000000..50cc9f9 --- /dev/null +++ b/lib/gitlab/client/snippets.rb @@ -0,0 +1,91 @@ +class Gitlab::Client + # Defines methods related to snippets. + # @see https://docs.gitlab.com/ce/api/project_snippets.html + module Snippets + # Gets a list of project's snippets. + # + # @example + # Gitlab.snippets(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Gitlab::ObjectifiedHash] + def snippets(project, options={}) + get("/projects/#{url_encode project}/snippets", query: options) + end + + # Gets information about a snippet. + # + # @example + # Gitlab.snippet(2, 14) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] + def snippet(project, id) + get("/projects/#{url_encode project}/snippets/#{id}") + end + + # Creates a new snippet. + # + # @example + # Gitlab.create_snippet(42, { title: 'REST', file_name: 'api.rb', code: 'some code' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :title (required) The title of a snippet. + # @option options [String] :file_name (required) The name of a snippet file. + # @option options [String] :code (required) The content of a snippet. + # @option options [String] :lifetime (optional) The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about created snippet. + def create_snippet(project, options={}) + post("/projects/#{url_encode project}/snippets", body: options) + end + + # Updates a snippet. + # + # @example + # Gitlab.edit_snippet(42, 34, { file_name: 'README.txt' }) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a snippet. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a snippet. + # @option options [String] :file_name The name of a snippet file. + # @option options [String] :code The content of a snippet. + # @option options [String] :lifetime The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about updated snippet. + def edit_snippet(project, id, options={}) + put("/projects/#{url_encode project}/snippets/#{id}", body: options) + end + + # Deletes a snippet. + # + # @example + # Gitlab.delete_snippet(2, 14) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about deleted snippet. + def delete_snippet(project, id) + delete("/projects/#{url_encode project}/snippets/#{id}") + end + + # Returns raw project snippet content as plain text. + # + # @example + # Gitlab.snippet_content(2, 14) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about deleted snippet. + def snippet_content(project, id) + get("/projects/#{url_encode project}/snippets/#{id}/raw", + format: nil, + headers: { Accept: 'text/plain' }, + parser: ::Gitlab::Request::Parser) + end + end +end diff --git a/lib/gitlab/client/system_hooks.rb b/lib/gitlab/client/system_hooks.rb new file mode 100644 index 0000000..fae3b51 --- /dev/null +++ b/lib/gitlab/client/system_hooks.rb @@ -0,0 +1,59 @@ +class Gitlab::Client + # Defines methods related to system hooks. + # @see https://docs.gitlab.com/ce/api/system_hooks.html + module SystemHooks + # Gets a list of system hooks. + # + # @example + # Gitlab.hooks + # Gitlab.system_hooks + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def hooks(options={}) + get("/hooks", query: options) + end + alias_method :system_hooks, :hooks + + # Adds a new system hook. + # + # @example + # Gitlab.add_hook('http://example.com/hook') + # Gitlab.add_system_hook('https://api.example.net/v1/hook') + # + # @param [String] url The hook URL. + # @return [Gitlab::ObjectifiedHash] + def add_hook(url) + post("/hooks", body: { url: url }) + end + alias_method :add_system_hook, :add_hook + + # Tests a system hook. + # + # @example + # Gitlab.hook(3) + # Gitlab.system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Array] + def hook(id) + get("/hooks/#{id}") + end + alias_method :system_hook, :hook + + # Deletes a new system hook. + # + # @example + # Gitlab.delete_hook(3) + # Gitlab.delete_system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Gitlab::ObjectifiedHash] + def delete_hook(id) + delete("/hooks/#{id}") + end + alias_method :delete_system_hook, :delete_hook + end +end diff --git a/lib/gitlab/client/tags.rb b/lib/gitlab/client/tags.rb new file mode 100644 index 0000000..393fccc --- /dev/null +++ b/lib/gitlab/client/tags.rb @@ -0,0 +1,96 @@ +class Gitlab::Client + # Defines methods related to tags. + # @see https://docs.gitlab.com/ce/api/tags.html + module Tags + # Gets a list of project repository tags. + # + # @example + # Gitlab.tags(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def tags(project, options={}) + get("/projects/#{url_encode project}/repository/tags", query: options) + end + alias_method :repo_tags, :tags + + # Creates a new project repository tag. + # + # @example + # Gitlab.create_tag(42, 'new_tag', 'master') + # Gitlab.create_tag(42, 'v1.0', 'master', 'Release 1.0') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] tag_name The name of the new tag. + # @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to. + # @param [String] message Optional message for tag, creates annotated tag if specified. + # @param [String] description Optional release notes for tag. + # @return [Gitlab::ObjectifiedHash] + def create_tag(project, tag_name, ref, message='', description=nil) + post("/projects/#{url_encode project}/repository/tags", body: { tag_name: tag_name, ref: ref, message: message, description: description }) + end + alias_method :repo_create_tag, :create_tag + + # Gets information about a repository tag. + # + # @example + # Gitlab.tag(3, 'api') + # Gitlab.repo_tag(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] tag The name of the tag. + # @return [Gitlab::ObjectifiedHash] + def tag(project, tag) + get("/projects/#{url_encode project}/repository/tags/#{tag}") + end + alias_method :repo_tag, :tag + + # Deletes a repository tag. Requires Gitlab >= 6.8.x + # + # @example + # Gitlab.delete_tag(3, 'api') + # Gitlab.repo_delete_tag(5, 'master') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] tag The name of the tag to delete + # @return [Gitlab::ObjectifiedHash] + def delete_tag(project, tag) + delete("/projects/#{url_encode project}/repository/tags/#{tag}") + end + alias_method :repo_delete_tag, :delete_tag + + # Adds release notes to an existing repository tag. Requires Gitlab >= 8.2.0 + # + # @example + # Gitlab.create_release(3, '1.0.0', 'This is ready for production') + # Gitlab.repo_create_release(5, '1.0.0', 'This is ready for production') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] tag The name of the new tag. + # @param [String] description Release notes with markdown support + # @return [Gitlab::ObjectifiedHash] + def create_release(project, tag, description) + post("/projects/#{url_encode project}/repository/tags/#{tag}/release", body: { description: description }) + end + alias_method :repo_create_release, :create_release + + # Updates the release notes of a given release. Requires Gitlab >= 8.2.0 + # + # @example + # Gitlab.update_release(3, '1.0.0', 'This is even more ready for production') + # Gitlab.repo_update_release(5, '1.0.0', 'This is even more ready for production') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] tag The name of the new tag. + # @param [String] description Release notes with markdown support + # @return [Gitlab::ObjectifiedHash] + def update_release(project, tag, description) + put("/projects/#{url_encode project}/repository/tags/#{tag}/release", body: { description: description }) + end + alias_method :repo_update_release, :update_release + + end +end diff --git a/lib/gitlab/client/users.rb b/lib/gitlab/client/users.rb new file mode 100644 index 0000000..6953f46 --- /dev/null +++ b/lib/gitlab/client/users.rb @@ -0,0 +1,250 @@ +class Gitlab::Client + # Defines methods related to users. + # @see https://docs.gitlab.com/ce/api/users.html + # @see https://docs.gitlab.com/ce/api/session.html + module Users + # Gets a list of users. + # + # @example + # Gitlab.users + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def users(options={}) + get("/users", query: options) + end + + # Gets information about a user. + # Will return information about an authorized user if no ID passed. + # + # @example + # Gitlab.user + # Gitlab.user(2) + # + # @param [Integer] id The ID of a user. + # @return [Gitlab::ObjectifiedHash] + def user(id=nil) + id.to_i.zero? ? get("/user") : get("/users/#{id}") + end + + # Creates a new user. + # Requires authentication from an admin account. + # + # @example + # Gitlab.create_user('joe@foo.org', 'secret', 'joe', { name: 'Joe Smith' }) + # or + # Gitlab.create_user('joe@foo.org', 'secret') + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @param [String] username The username of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def create_user(*args) + options = Hash === args.last ? args.pop : {} + if args[2] + body = { email: args[0], password: args[1], username: args[2] } + else + body = { email: args[0], password: args[1], name: args[0] } + end + body.merge!(options) + post('/users', body: body) + end + + # Updates a user. + # + # @example + # Gitlab.edit_user(15, { email: 'joe.smith@foo.org', projects_limit: 20 }) + # + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] :email The email of a user. + # @option options [String] :password The password of a user. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def edit_user(user_id, options={}) + put("/users/#{user_id}", body: options) + end + + # Deletes a user. + # + # @example + # Gitlab.delete_user(1) + # + # @param [Integer] id The ID of a user. + # @return [Gitlab::ObjectifiedHash] Information about deleted user. + def delete_user(user_id) + delete("/users/#{user_id}") + end + + # Blocks the specified user. Available only for admin. + # + # @example + # Gitlab.block_user(15) + # + # @param [Integer] user_id The Id of user + # @return [Boolean] success or not + def block_user(user_id) + post("/users/#{user_id}/block") + end + + # Unblocks the specified user. Available only for admin. + # + # @example + # Gitlab.unblock_user(15) + # + # @param [Integer] user_id The Id of user + # @return [Boolean] success or not + def unblock_user(user_id) + post("/users/#{user_id}/unblock") + end + + # Creates a new user session. + # + # @example + # Gitlab.session('jack@example.com', 'secret12345') + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @return [Gitlab::ObjectifiedHash] + # @note This method doesn't require private_token to be set. + def session(email, password) + post("/session", body: { email: email, password: password }, unauthenticated: true) + end + + # Gets a list of user's SSH keys. + # + # @example + # Gitlab.ssh_keys + # Gitlab.ssh_keys({ user_id: 2 }) + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @option options [Integer] :user_id The ID of the user to retrieve the keys for. + # @return [Array] + def ssh_keys(options={}) + user_id = options.delete :user_id + if user_id.to_i.zero? + get("/user/keys", query: options) + else + get("/users/#{user_id}/keys", query: options) + end + end + + # Gets information about SSH key. + # + # @example + # Gitlab.ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] + def ssh_key(id) + get("/user/keys/#{id}") + end + + # Creates a new SSH key. + # + # @example + # Gitlab.create_ssh_key('key title', 'key body') + # + # @param [String] title The title of an SSH key. + # @param [String] key The SSH key body. + # @return [Gitlab::ObjectifiedHash] Information about created SSH key. + def create_ssh_key(title, key) + post("/user/keys", body: { title: title, key: key }) + end + + # Deletes an SSH key. + # + # @example + # Gitlab.delete_ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] Information about deleted SSH key. + def delete_ssh_key(id) + delete("/user/keys/#{id}") + end + + # Gets user emails. + # Will return emails an authorized user if no user ID passed. + # + # @example + # Gitlab.emails + # Gitlab.emails(2) + # + # @param [Integer] user_id The ID of a user. + # @return [Gitlab::ObjectifiedHash] + def emails(user_id=nil) + url = user_id.to_i.zero? ? "/user/emails" : "/users/#{user_id}/emails" + get(url) + end + + # Get a single email. + # + # @example + # Gitlab.email(3) + # + # @param [Integer] id The ID of a email. + # @return [Gitlab::ObjectifiedHash] + def email(id) + get("/user/emails/#{id}") + end + + # Creates a new email + # Will create a new email an authorized user if no user ID passed. + # + # @example + # Gitlab.add_email('email@example.com') + # Gitlab.add_email('email@example.com', 2) + # + # @param [String] email Email address + # @param [Integer] user_id The ID of a user. + # @return [Gitlab::ObjectifiedHash] + def add_email(email, user_id=nil) + url = user_id.to_i.zero? ? "/user/emails" : "/users/#{user_id}/emails" + post(url, body: {email: email}) + end + + # Delete email + # Will delete a email an authorized user if no user ID passed. + # + # @example + # Gitlab.delete_email(2) + # Gitlab.delete_email(3, 2) + # + # @param [Integer] id Email address ID + # @param [Integer] user_id The ID of a user. + # @return [Boolean] + def delete_email(id, user_id=nil) + url = user_id.to_i.zero? ? "/user/emails/#{id}" : "/users/#{user_id}/emails/#{id}" + delete(url) + end + + # Search for groups by name + # + # @example + # Gitlab.user_search('gitlab') + # + # @param [String] search A string to search for in user names and paths. + # @param [Hash] options A customizable set of options. + # @option options [String] :per_page Number of user to return per page + # @option options [String] :page The page to retrieve + # @return [Array] + def user_search(search, options={}) + options[:search] = search + get("/users", query: options) + end + end +end diff --git a/lib/gitlab/client.rb b/lib/gitlab/client.rb new file mode 100644 index 0000000..3684d94 --- /dev/null +++ b/lib/gitlab/client.rb @@ -0,0 +1,54 @@ +module Gitlab + # Wrapper for the Gitlab REST API. + class Client < API + Dir[File.expand_path('../client/*.rb', __FILE__)].each { |f| require f } + + include Branches + include Builds + include BuildVariables + include Commits + include Groups + include Issues + include Keys + include Labels + include MergeRequests + include Milestones + include Namespaces + include Notes + include Pipelines + include PipelineTriggers + include Projects + include Repositories + include RepositoryFiles + include Runners + include Services + include Snippets + include SystemHooks + include Tags + include Users + include Jobs + + # Text representation of the client, masking private token. + # + # @return [String] + def inspect + inspected = super + + if @private_token + inspected = inspected.sub! @private_token, only_show_last_four_chars(@private_token) + end + + inspected + end + + def url_encode(s) + ERB::Util.url_encode(s) + end + + private + + def only_show_last_four_chars(token) + "#{'*'*(token.size - 4)}#{token[-4..-1]}" + end + end +end diff --git a/lib/gitlab/configuration.rb b/lib/gitlab/configuration.rb new file mode 100644 index 0000000..a9a961c --- /dev/null +++ b/lib/gitlab/configuration.rb @@ -0,0 +1,55 @@ +require 'gitlab/cli_helpers' +module Gitlab + # Defines constants and methods related to configuration. + module Configuration + # An array of valid keys in the options hash when configuring a Gitlab::API. + VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze + + # The user agent that will be sent to the API endpoint if none is set. + DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze + + # @private + attr_accessor(*VALID_OPTIONS_KEYS) + # @private + alias_method :auth_token=, :private_token= + + # Sets all configuration options to their default values + # when this module is extended. + def self.extended(base) + base.reset + end + + # Convenience method to allow configuration options to be set in a block. + def configure + yield self + end + + # Creates a hash of options and their values. + def options + VALID_OPTIONS_KEYS.inject({}) do |option, key| + option.merge!(key => send(key)) + end + end + + # Resets all configuration options to the defaults. + def reset + self.endpoint = ENV['GITLAB_API_ENDPOINT'] + self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] || ENV['GITLAB_API_AUTH_TOKEN'] + self.httparty = get_httparty_config(ENV['GITLAB_API_HTTPARTY_OPTIONS']) + self.sudo = nil + self.user_agent = DEFAULT_USER_AGENT + end + + private + + # Allows HTTParty config to be specified in ENV using YAML hash. + def get_httparty_config(options) + return options if options.nil? + + httparty = Gitlab::CLI::Helpers.yaml_load(options) + + raise ArgumentError, "HTTParty config should be a Hash." unless httparty.is_a? Hash + Gitlab::CLI::Helpers.symbolize_keys httparty + end + end +end diff --git a/lib/gitlab/error.rb b/lib/gitlab/error.rb new file mode 100644 index 0000000..ce10d0d --- /dev/null +++ b/lib/gitlab/error.rb @@ -0,0 +1,85 @@ +module Gitlab + module Error + # Custom error class for rescuing from all Gitlab errors. + class Error < StandardError; end + + # Raised when API endpoint credentials not configured. + class MissingCredentials < Error; end + + # Raised when impossible to parse response body. + class Parsing < Error; end + + # Custom error class for rescuing from HTTP response errors. + class ResponseError < Error + def initialize(response) + @response = response + super(build_error_message) + end + + # Status code returned in the http response. + # + # @return [Integer] + def response_status + @response.code + end + + private + + # Human friendly message. + # + # @return [String] + def build_error_message + parsed_response = @response.parsed_response + message = parsed_response.message || parsed_response.error + + "Server responded with code #{@response.code}, message: " \ + "#{handle_message(message)}. " \ + "Request URI: #{@response.request.base_uri}#{@response.request.path}" + end + + # Handle error response message in case of nested hashes + def handle_message(message) + case message + when Gitlab::ObjectifiedHash + message.to_h.sort.map do |key, val| + "'#{key}' #{(val.is_a?(Hash) ? val.sort.map { |k, v| "(#{k}: #{v.join(' ')})" } : val).join(' ')}" + end.join(', ') + when Array + message.join(' ') + else + message + end + end + end + + # Raised when API endpoint returns the HTTP status code 400. + class BadRequest < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 401. + class Unauthorized < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 403. + class Forbidden < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 404. + class NotFound < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 405. + class MethodNotAllowed < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 409. + class Conflict < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 422. + class Unprocessable < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 500. + class InternalServerError < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 502. + class BadGateway < ResponseError; end + + # Raised when API endpoint returns the HTTP status code 503. + class ServiceUnavailable < ResponseError; end + end +end diff --git a/lib/gitlab/file_response.rb b/lib/gitlab/file_response.rb new file mode 100644 index 0000000..7a8ed6a --- /dev/null +++ b/lib/gitlab/file_response.rb @@ -0,0 +1,46 @@ +module Gitlab + # Wrapper class of file response. + class FileResponse + HEADER_CONTENT_DISPOSITION = 'Content-Disposition'.freeze + + attr_reader :filename + + def initialize(file) + @file = file + end + + # @return [bool] Always false + def empty? + false + end + + # @return [Hash] A hash consisting of filename and io object + def to_hash + { filename: @filename, data: @file } + end + alias_method :to_h, :to_hash + + # @return [String] Formatted string with the class name, object id and filename. + def inspect + "#<#{self.class}:#{object_id} {filename: #{filename.inspect}}>" + end + + def method_missing(name, *args, &block) + if @file.respond_to?(name) + @file.send(name, *args, &block) + else + super + end + end + + def respond_to_missing?(method_name, include_private = false) + super || @file.respond_to?(method_name, include_private) + end + + # Parse filename from the 'Content Disposition' header. + def parse_headers!(headers) + @filename = headers[HEADER_CONTENT_DISPOSITION].split("filename=")[1] + @filename = @filename[1...-1] if @filename[0] == '"' # Unquote filenames + end + end +end diff --git a/lib/gitlab/help.rb b/lib/gitlab/help.rb new file mode 100644 index 0000000..9037533 --- /dev/null +++ b/lib/gitlab/help.rb @@ -0,0 +1,95 @@ +require 'gitlab' +require 'gitlab/cli_helpers' + +module Gitlab::Help + extend Gitlab::CLI::Helpers + + class << self + # Returns the (modified) help from the 'ri' command or returns an error. + # + # @return [String] + def get_help(cmd) + cmd_namespace = namespace cmd + + if cmd_namespace + ri_output = `#{ri_cmd} -T #{cmd_namespace} 2>&1`.chomp + + if $CHILD_STATUS == 0 + change_help_output! cmd, ri_output + yield ri_output if block_given? + + ri_output + else + "Ri docs not found for #{cmd}, please install the docs to use 'help'." + end + else + "Unknown command: #{cmd}." + end + end + + # Finds the location of 'ri' on a system. + # + # @return [String] + def ri_cmd + which_ri = `which ri`.chomp + if which_ri.empty? + fail "'ri' tool not found in $PATH. Please install it to use the help." + end + + which_ri + end + + # A hash map that contains help topics (Branches, Groups, etc.) + # and a list of commands that are defined under a topic (create_branch, + # branches, protect_branch, etc.). + # + # @return [Hash] + def help_map + @help_map ||= begin + actions.each_with_object({}) do |action, hsh| + key = client.method(action). + owner.to_s.gsub(/Gitlab::(?:Client::)?/, '') + hsh[key] ||= [] + hsh[key] << action.to_s + end + end + end + + # Table with available commands. + # + # @return [Terminal::Table] + def actions_table(topic=nil) + rows = topic ? help_map[topic] : help_map.keys + table do |t| + t.title = topic || "Help Topics" + + # add_row expects an array and we have strings hence the map. + rows.sort.map { |r| [r] }.each_with_index do |row, index| + t.add_row row + t.add_separator unless rows.size - 1 == index + end + end + end + + # Returns full namespace of a command (e.g. Gitlab::Client::Branches.cmd) + def namespace(cmd) + method_owners.select { |method| method[:name] === cmd }. + map { |method| method[:owner] + '.' + method[:name] }. + shift + end + + # Massage output from 'ri'. + def change_help_output!(cmd, output_str) + output_str.gsub!(/#{cmd}\((.*?)\)/m, cmd + ' \1') + output_str.gsub!(/\,[\s]*/, ' ') + + # Ensure @option descriptions are on a single line + output_str.gsub!(/\n\[/, " \[") + output_str.gsub!(/\s(@)/, "\n@") + output_str.gsub!(/(\])\n(\:)/, '\1 \2') + output_str.gsub!(/(\:.*)(\n)(.*\.)/, '\1 \3') + output_str.gsub!(/\{(.+)\}/, '"{\1}"') + + end + end # class << self +end diff --git a/lib/gitlab/objectified_hash.rb b/lib/gitlab/objectified_hash.rb new file mode 100644 index 0000000..571ad49 --- /dev/null +++ b/lib/gitlab/objectified_hash.rb @@ -0,0 +1,34 @@ +module Gitlab + # Converts hashes to the objects. + class ObjectifiedHash + # Creates a new ObjectifiedHash object. + def initialize(hash) + @hash = hash + @data = hash.inject({}) do |data, (key, value)| + value = ObjectifiedHash.new(value) if value.is_a? Hash + data[key.to_s] = value + data + end + end + + # @return [Hash] The original hash. + def to_hash + @hash + end + alias_method :to_h, :to_hash + + # @return [String] Formatted string with the class name, object id and original hash. + def inspect + "#<#{self.class}:#{object_id} {hash: #{@hash.inspect}}" + end + + # Delegate to ObjectifiedHash. + def method_missing(key) + @data.key?(key.to_s) ? @data[key.to_s] : nil + end + + def respond_to_missing?(method_name, include_private = false) + @hash.keys.map(&:to_sym).include?(method_name.to_sym) || super + end + end +end diff --git a/lib/gitlab/page_links.rb b/lib/gitlab/page_links.rb new file mode 100644 index 0000000..00aba19 --- /dev/null +++ b/lib/gitlab/page_links.rb @@ -0,0 +1,33 @@ +module Gitlab + # Parses link header. + # + # @private + class PageLinks + HEADER_LINK = 'Link'.freeze + DELIM_LINKS = ','.freeze + LINK_REGEX = /<([^>]+)>; rel=\"([^\"]+)\"/ + METAS = %w(last next first prev) + + attr_accessor(*METAS) + + def initialize(headers) + link_header = headers[HEADER_LINK] + + if link_header && link_header =~ /(next|first|last|prev)/ + extract_links(link_header) + end + end + + private + + def extract_links(header) + header.split(DELIM_LINKS).each do |link| + LINK_REGEX.match(link.strip) do |match| + url, meta = match[1], match[2] + next if !url || !meta || METAS.index(meta).nil? + self.send("#{meta}=", url) + end + end + end + end +end diff --git a/lib/gitlab/paginated_response.rb b/lib/gitlab/paginated_response.rb new file mode 100644 index 0000000..186d0db --- /dev/null +++ b/lib/gitlab/paginated_response.rb @@ -0,0 +1,97 @@ +module Gitlab + # Wrapper class of paginated response. + class PaginatedResponse + attr_accessor :client + + def initialize(array) + @array = array + end + + def ==(other) + @array == other + end + + def inspect + @array.inspect + end + + def method_missing(name, *args, &block) + if @array.respond_to?(name) + @array.send(name, *args, &block) + else + super + end + end + + def respond_to_missing?(method_name, include_private = false) + super || @array.respond_to?(method_name, include_private) + end + + def parse_headers!(headers) + @links = PageLinks.new headers + end + + def each_page + current = self + yield current + while current.has_next_page? + current = current.next_page + yield current + end + end + + def auto_paginate + response = block_given? ? nil : [] + each_page do |page| + if block_given? + page.each do |item| + yield item + end + else + response += page + end + end + response + end + + def has_last_page? + !(@links.nil? || @links.last.nil?) + end + + def last_page + return nil if @client.nil? || !has_last_page? + path = @links.last.sub(/#{@client.endpoint}/, '') + @client.get(path) + end + + def has_first_page? + !(@links.nil? || @links.first.nil?) + end + + def first_page + return nil if @client.nil? || !has_first_page? + path = @links.first.sub(/#{@client.endpoint}/, '') + @client.get(path) + end + + def has_next_page? + !(@links.nil? || @links.next.nil?) + end + + def next_page + return nil if @client.nil? || !has_next_page? + path = @links.next.sub(/#{@client.endpoint}/, '') + @client.get(path) + end + + def has_prev_page? + !(@links.nil? || @links.prev.nil?) + end + + def prev_page + return nil if @client.nil? || !has_prev_page? + path = @links.prev.sub(/#{@client.endpoint}/, '') + @client.get(path) + end + end +end diff --git a/lib/gitlab/request.rb b/lib/gitlab/request.rb new file mode 100644 index 0000000..d146e4b --- /dev/null +++ b/lib/gitlab/request.rb @@ -0,0 +1,120 @@ +require 'httparty' +require 'json' + +module Gitlab + # @private + class Request + include HTTParty + format :json + headers 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded' + parser proc { |body, _| parse(body) } + + attr_accessor :private_token, :endpoint + + # Converts the response body to an ObjectifiedHash. + def self.parse(body) + body = decode(body) + + if body.is_a? Hash + ObjectifiedHash.new body + elsif body.is_a? Array + PaginatedResponse.new(body.collect! { |e| ObjectifiedHash.new(e) }) + elsif body + true + elsif !body + false + elsif body.nil? + false + else + raise Error::Parsing.new "Couldn't parse a response body" + end + end + + # Decodes a JSON response into Ruby object. + def self.decode(response) + JSON.load response + rescue JSON::ParserError + raise Error::Parsing.new "The response is not a valid JSON" + end + + def get(path, options={}) + set_httparty_config(options) + set_authorization_header(options) + validate self.class.get(@endpoint + path, options) + end + + def post(path, options={}) + set_httparty_config(options) + set_authorization_header(options) + validate self.class.post(@endpoint + path, options) + end + + def put(path, options={}) + set_httparty_config(options) + set_authorization_header(options) + validate self.class.put(@endpoint + path, options) + end + + def delete(path, options={}) + set_httparty_config(options) + set_authorization_header(options) + validate self.class.delete(@endpoint + path, options) + end + + # Checks the response code for common errors. + # Returns parsed response for successful requests. + def validate(response) + error_klass = case response.code + when 400 then Error::BadRequest + when 401 then Error::Unauthorized + when 403 then Error::Forbidden + when 404 then Error::NotFound + when 405 then Error::MethodNotAllowed + when 409 then Error::Conflict + when 422 then Error::Unprocessable + when 500 then Error::InternalServerError + when 502 then Error::BadGateway + when 503 then Error::ServiceUnavailable + end + + fail error_klass.new(response) if error_klass + + parsed = response.parsed_response + parsed.client = self if parsed.respond_to?(:client=) + parsed.parse_headers!(response.headers) if parsed.respond_to?(:parse_headers!) + parsed + end + + # Sets a base_uri and default_params for requests. + # @raise [Error::MissingCredentials] if endpoint not set. + def set_request_defaults(sudo=nil) + self.class.default_params sudo: sudo + raise Error::MissingCredentials.new("Please set an endpoint to API") unless @endpoint + self.class.default_params.delete(:sudo) if sudo.nil? + end + + private + + # Sets a PRIVATE-TOKEN or Authorization header for requests. + # + # @param [Hash] options A customizable set of options. + # @option options [Boolean] :unauthenticated true if the API call does not require user authentication. + # @raise [Error::MissingCredentials] if private_token and auth_token are not set. + def set_authorization_header(options) + unless options[:unauthenticated] + raise Error::MissingCredentials.new("Please provide a private_token or auth_token for user") unless @private_token + if @private_token.length <= 20 + options[:headers] = { 'PRIVATE-TOKEN' => @private_token } + else + options[:headers] = { 'Authorization' => "Bearer #{@private_token}" } + end + end + end + + # Set HTTParty configuration + # @see https://github.com/jnunemaker/httparty + def set_httparty_config(options) + options.merge!(httparty) if httparty + end + end +end diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb new file mode 100644 index 0000000..0616b3f --- /dev/null +++ b/lib/gitlab/shell.rb @@ -0,0 +1,84 @@ +require 'gitlab' +require 'gitlab/help' +require 'gitlab/cli_helpers' +require 'gitlab/shell_history' +require 'readline' +require 'shellwords' + +class Gitlab::Shell + extend Gitlab::CLI::Helpers + + class << self + attr_reader :arguments, :command + + def start + trap('INT') { quit_shell } # capture ctrl-c + setup + + while buffer = Readline.readline('gitlab> ') + begin + parse_input buffer + + @arguments.map! { |arg| symbolize_keys(yaml_load(arg)) } + + case buffer + when nil, '' + next + when 'exit' + quit_shell + when /^\bhelp\b+/ + puts help(arguments[0]) { |out| out.gsub!(/Gitlab\./, 'gitlab> ') } + else + history << buffer + + data = execute command, arguments + output_table command, arguments, data + end + rescue => e + puts e.message + end + end + + quit_shell # save history if user presses ctrl-d + end + + def parse_input(buffer) + buf = Shellwords.shellwords(buffer) + + @command = buf.shift + @arguments = buf.count > 0 ? buf : [] + end + + def setup + history.load + + Readline.completion_proc = completion + Readline.completion_append_character = ' ' + end + + # Gets called when user hits TAB key to do completion + def completion + proc { |str| actions.map(&:to_s).grep(/^#{Regexp.escape(str)}/) } + end + + # Execute a given command with arguements + def execute(cmd=command, args=arguments) + if actions.include?(cmd.to_sym) + confirm_command(cmd) + gitlab_helper(cmd, args) + else + fail "Unknown command: #{cmd}. " \ + "See the 'help' for a list of valid commands." + end + end + + def quit_shell + history.save + exit + end + + def history + @history ||= History.new + end + end # class << self +end diff --git a/lib/gitlab/shell_history.rb b/lib/gitlab/shell_history.rb new file mode 100644 index 0000000..8e9435d --- /dev/null +++ b/lib/gitlab/shell_history.rb @@ -0,0 +1,59 @@ +class Gitlab::Shell + class History + DEFAULT_HISTFILESIZE = 200 + DEFAULT_FILE_PATH = File.join(Dir.home, '.gitlab_shell_history') + + def initialize(options={}) + @file_path = options[:file_path] || DEFAULT_FILE_PATH + Readline::HISTORY.clear + end + + def load + read_from_file { |line| Readline::HISTORY << line.chomp } + end + + def save + lines.each { |line| history_file.puts line if history_file } + end + + def push(line) + Readline::HISTORY << line + end + alias_method :<<, :push + + def lines + Readline::HISTORY.to_a.last(max_lines) + end + + private + + def history_file + if defined?(@history_file) + @history_file + else + @history_file = File.open(history_file_path, 'w', 0600).tap do |file| + file.sync = true + end + end + rescue Errno::EACCES + warn 'History not saved; unable to open your history file for writing.' + @history_file = false + end + + def history_file_path + File.expand_path(@file_path) + end + + def read_from_file + path = history_file_path + + File.foreach(path) { |line| yield(line) } if File.exist?(path) + rescue => error + warn "History file not loaded: #{error.message}" + end + + def max_lines + (ENV['GITLAB_HISTFILESIZE'] || DEFAULT_HISTFILESIZE).to_i + end + end +end diff --git a/lib/gitlab/version.rb b/lib/gitlab/version.rb new file mode 100644 index 0000000..4c8f93b --- /dev/null +++ b/lib/gitlab/version.rb @@ -0,0 +1,3 @@ +module Gitlab + VERSION = "4.1.0" +end diff --git a/lib/gitlab.rb b/lib/gitlab.rb new file mode 100644 index 0000000..a3ac3eb --- /dev/null +++ b/lib/gitlab.rb @@ -0,0 +1,45 @@ +require 'gitlab/version' +require 'gitlab/objectified_hash' +require 'gitlab/configuration' +require 'gitlab/error' +require 'gitlab/page_links' +require 'gitlab/paginated_response' +require 'gitlab/file_response' +require 'gitlab/request' +require 'gitlab/api' +require 'gitlab/client' + +module Gitlab + extend Configuration + + # Alias for Gitlab::Client.new + # + # @return [Gitlab::Client] + def self.client(options={}) + Gitlab::Client.new(options) + end + + # Delegate to Gitlab::Client + def self.method_missing(method, *args, &block) + return super unless client.respond_to?(method) + client.send(method, *args, &block) + end + + # Delegate to Gitlab::Client + def respond_to_missing?(method_name, include_private = false) + client.respond_to?(method_name) || super + end + + # Delegate to HTTParty.http_proxy + def self.http_proxy(address=nil, port=nil, username=nil, password=nil) + Gitlab::Request.http_proxy(address, port, username, password) + end + + # Returns an unsorted array of available client methods. + # + # @return [Array] + def self.actions + hidden = /endpoint|private_token|auth_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults|httparty/ + (Gitlab::Client.instance_methods - Object.methods).reject { |e| e[hidden] } + end +end diff --git a/spec/fixtures/branch.json b/spec/fixtures/branch.json new file mode 100644 index 0000000..34a0208 --- /dev/null +++ b/spec/fixtures/branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected": true} diff --git a/spec/fixtures/branch_delete.json b/spec/fixtures/branch_delete.json new file mode 100644 index 0000000..4ec8edb --- /dev/null +++ b/spec/fixtures/branch_delete.json @@ -0,0 +1,3 @@ +{ + "branch_name": "api" +} diff --git a/spec/fixtures/branches.json b/spec/fixtures/branches.json new file mode 100644 index 0000000..05a3944 --- /dev/null +++ b/spec/fixtures/branches.json @@ -0,0 +1 @@ +[{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"}},{"name":"dashboard-feed","commit":{"id":"f8f6ff065eccc6ede4d35ed87a09bb962b84ca25","parents":[{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e"}],"tree":"e17f2157143d550891d4669c10b7446e4739bc6d","message":"add projects atom feed","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-31T23:42:02-07:00","committed_date":"2012-05-31T23:42:02-07:00"}},{"name":"master","commit":{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e","parents":[{"id":"af226ae9c9af406c8a0e0bbdf364563495c2f432"},{"id":"e851cb07762aa464aae10e8b4b28de87c1a6f925"}],"tree":"6c6845838039f01723d91f395a1d2fa1dcc82522","message":"Merge pull request #868 from SaitoWu/bugfix/encoding\n\nBugfix/encoding","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-30T00:24:43-07:00","committed_date":"2012-05-30T00:24:43-07:00"}},{"name":"preview_notes","commit":{"id":"3749e0d99ac6bfbc65889b1b7a5310e14e7fe89a","parents":[{"id":"2483181f2c3d4ea7d2c68147b19bc07fc3937b0c"}],"tree":"f8c56161b0d6561568f088df9961362eb1ece88b","message":"pass project_id to notes preview path","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-08-09T23:46:27-07:00","committed_date":"2012-08-09T23:46:27-07:00"}},{"name":"refactoring","commit":{"id":"7c7761099cae83f59fe5780340e100be890847b2","parents":[{"id":"058d80b3363dd4fc4417ca4f60f76119188a2470"}],"tree":"d7d4a94c700dc0e84ee943019213d2358a49c413","message":"fix deprecation warnings","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-29T07:16:28-07:00","committed_date":"2012-05-29T07:16:28-07:00"}}] diff --git a/spec/fixtures/build.json b/spec/fixtures/build.json new file mode 100644 index 0000000..c0c9b2f --- /dev/null +++ b/spec/fixtures/build.json @@ -0,0 +1,38 @@ +{ + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.880Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:31.198Z", + "id": 8, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:30.733Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "is_admin": true, + "linkedin": "", + "name": "John Smith", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } +} \ No newline at end of file diff --git a/spec/fixtures/build_artifacts.json b/spec/fixtures/build_artifacts.json new file mode 100644 index 0000000..6851e34 Binary files /dev/null and b/spec/fixtures/build_artifacts.json differ diff --git a/spec/fixtures/build_cancel.json b/spec/fixtures/build_cancel.json new file mode 100644 index 0000000..dd54823 --- /dev/null +++ b/spec/fixtures/build_cancel.json @@ -0,0 +1,24 @@ +{ + "commit": { + "author_email": "admin@example.com", + "author_name": "John Smith", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2016-01-11T10:13:33.506Z", + "download_url": null, + "finished_at": "2016-01-11T10:14:09.526Z", + "id": 69, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "canceled", + "tag": false, + "user": null +} \ No newline at end of file diff --git a/spec/fixtures/build_erase.json b/spec/fixtures/build_erase.json new file mode 100644 index 0000000..d745979 --- /dev/null +++ b/spec/fixtures/build_erase.json @@ -0,0 +1,24 @@ +{ + "commit": { + "author_email": "admin@example.com", + "author_name": "John Smith", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "download_url": null, + "id": 69, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "created_at": "2016-01-11T10:13:33.506Z", + "started_at": "2016-01-11T10:13:33.506Z", + "finished_at": "2016-01-11T10:15:10.506Z", + "status": "failed", + "tag": false, + "user": null +} diff --git a/spec/fixtures/build_retry.json b/spec/fixtures/build_retry.json new file mode 100644 index 0000000..04ddb26 --- /dev/null +++ b/spec/fixtures/build_retry.json @@ -0,0 +1,24 @@ +{ + "commit": { + "author_email": "admin@example.com", + "author_name": "John Smith", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2016-01-11T10:13:33.506Z", + "download_url": null, + "finished_at": null, + "id": 69, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending", + "tag": false, + "user": null +} \ No newline at end of file diff --git a/spec/fixtures/builds.json b/spec/fixtures/builds.json new file mode 100644 index 0000000..1b93d75 --- /dev/null +++ b/spec/fixtures/builds.json @@ -0,0 +1,78 @@ +[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.802Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:27.895Z", + "id": 7, + "name": "teaspoon", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:27.722Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.727Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:24.921Z", + "id": 6, + "name": "spinach:other", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:24.729Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } + } +] \ No newline at end of file diff --git a/spec/fixtures/builds_commits.json b/spec/fixtures/builds_commits.json new file mode 100644 index 0000000..ba08b72 --- /dev/null +++ b/spec/fixtures/builds_commits.json @@ -0,0 +1,64 @@ +[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2016-01-11T10:13:33.506Z", + "download_url": null, + "finished_at": "2016-01-11T10:14:09.526Z", + "id": 69, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "canceled", + "tag": false, + "user": null + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.957Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:33.913Z", + "id": 9, + "name": "brakeman", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:33.727Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } + } +] \ No newline at end of file diff --git a/spec/fixtures/compare_merge_request_diff.json b/spec/fixtures/compare_merge_request_diff.json new file mode 100644 index 0000000..e4bc855 --- /dev/null +++ b/spec/fixtures/compare_merge_request_diff.json @@ -0,0 +1,31 @@ + +{ + "commit": { + "id": "12d65c8dd2b2676fa3ac47d955accc085a37a9c1", + "short_id": "12d65c8dd2b", + "title": "JS fix", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2014-02-27T10:27:00+02:00" + }, + "commits": [{ + "id": "12d65c8dd2b2676fa3ac47d955accc085a37a9c1", + "short_id": "12d65c8dd2b", + "title": "JS fix", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2014-02-27T10:27:00+02:00" + }], + "diffs": [{ + "old_path": "files/js/application.js", + "new_path": "files/js/application.js", + "a_mode": null, + "b_mode": "100644", + "diff": "--- a/files/js/application.js\n+++ b/files/js/application.js\n@@ -24,8 +24,10 @@\n //= require g.raphael-min\n //= require g.bar-min\n //= require branch-graph\n-//= require highlightjs.min\n-//= require ace/ace\n //= require_tree .\n //= require d3\n //= require underscore\n+\n+function fix() { \n+ alert(\"Fixed\")\n+}", + "new_file": false, + "renamed_file": false, + "deleted_file": false + }], + "compare_timeout": false, + "compare_same_ref": false +} diff --git a/spec/fixtures/empty.json b/spec/fixtures/empty.json new file mode 100644 index 0000000..e69de29 diff --git a/spec/fixtures/error_already_exists.json b/spec/fixtures/error_already_exists.json new file mode 100644 index 0000000..d1070f5 --- /dev/null +++ b/spec/fixtures/error_already_exists.json @@ -0,0 +1 @@ +{"message": "409 Already exists"} \ No newline at end of file diff --git a/spec/fixtures/error_project_not_found.json b/spec/fixtures/error_project_not_found.json new file mode 100644 index 0000000..f0d4e3a --- /dev/null +++ b/spec/fixtures/error_project_not_found.json @@ -0,0 +1 @@ +{"message": "404 Project Not Found"} diff --git a/spec/fixtures/get_repository_file.json b/spec/fixtures/get_repository_file.json new file mode 100644 index 0000000..a5120eb --- /dev/null +++ b/spec/fixtures/get_repository_file.json @@ -0,0 +1 @@ +{"file_name":"README.md", "file_path":"README.md", "size":"19", "encoding":"base64", "content":"VGhpcyBpcyBhICpSRUFETUUqIQ==\n", "ref":"master", "blob_id":"0eba9dff767611060181e0423a1de2941d27efc8", "commit_id":"eb38397cb6ae669219e6bc18ad19981fff18ea29"} diff --git a/spec/fixtures/group.json b/spec/fixtures/group.json new file mode 100644 index 0000000..bce3581 --- /dev/null +++ b/spec/fixtures/group.json @@ -0,0 +1,60 @@ +{"id": 10, "name": "GitLab-Group", "path": "gitlab-group", "owner_id": 6, "projects": [ + { + "id": 9, + "name": "mojito", + "description": null, + "default_branch": "master", + "owner": { + "id": 6, + "username": "jose", + "email": "jose@abc.com", + "name": "Jose Jose", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "mojito", + "path_with_namespace": "gitlab-group/mojito", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T16:59:15Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + }, + { + "id": 10, + "name": "gitlabhq", + "description": null, + "default_branch": null, + "owner": { + "id": 6, + "username": "randx", + "email": "randx@github.com", + "name": "Dmitry Z", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "gitlabhq", + "path_with_namespace": "gitlab-group/gitlabhq", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T17:02:31Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + } +]} \ No newline at end of file diff --git a/spec/fixtures/group_create.json b/spec/fixtures/group_create.json new file mode 100644 index 0000000..67445f6 --- /dev/null +++ b/spec/fixtures/group_create.json @@ -0,0 +1 @@ +{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1} \ No newline at end of file diff --git a/spec/fixtures/group_create_with_description.json b/spec/fixtures/group_create_with_description.json new file mode 100644 index 0000000..326e726 --- /dev/null +++ b/spec/fixtures/group_create_with_description.json @@ -0,0 +1 @@ +{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1,"description":"gitlab group description"} \ No newline at end of file diff --git a/spec/fixtures/group_delete.json b/spec/fixtures/group_delete.json new file mode 100644 index 0000000..a304bce --- /dev/null +++ b/spec/fixtures/group_delete.json @@ -0,0 +1 @@ +{"id":42,"name":"Gitlab-Group","path":"gitlab-group","created_at":"2016-02-24T20:16:42.906Z","updated_at":"2016-02-24T20:16:42.906Z"} diff --git a/spec/fixtures/group_member.json b/spec/fixtures/group_member.json new file mode 100644 index 0000000..feef543 --- /dev/null +++ b/spec/fixtures/group_member.json @@ -0,0 +1 @@ +{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":10} \ No newline at end of file diff --git a/spec/fixtures/group_member_delete.json b/spec/fixtures/group_member_delete.json new file mode 100644 index 0000000..ff052ed --- /dev/null +++ b/spec/fixtures/group_member_delete.json @@ -0,0 +1 @@ +{"created_at":"2013-09-04T18:18:15Z","group_access":10,"group_id":3,"id":2,"notification_level":3,"updated_at":"2013-09-04T18:18:15Z","user_id":2} \ No newline at end of file diff --git a/spec/fixtures/group_member_edit.json b/spec/fixtures/group_member_edit.json new file mode 100644 index 0000000..324f730 --- /dev/null +++ b/spec/fixtures/group_member_edit.json @@ -0,0 +1 @@ +{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":50} \ No newline at end of file diff --git a/spec/fixtures/group_members.json b/spec/fixtures/group_members.json new file mode 100644 index 0000000..02ddc10 --- /dev/null +++ b/spec/fixtures/group_members.json @@ -0,0 +1 @@ +[{"id":1,"username":"eraymond","email":"eraymond@local.host","name":"Edward Raymond","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50},{"id":1,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50}] \ No newline at end of file diff --git a/spec/fixtures/group_projects.json b/spec/fixtures/group_projects.json new file mode 100644 index 0000000..23211e2 --- /dev/null +++ b/spec/fixtures/group_projects.json @@ -0,0 +1,44 @@ +[ + { + "id": 4, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", + "web_url": "http://example.com/diaspora/diaspora-client", + "tag_list": [ + "example", + "disapora client" + ], + "owner": { + "id": 3, + "name": "Diaspora", + "created_at": "2013-09-30T13: 46: 02Z" + }, + "name": "Diaspora Client", + "name_with_namespace": "Diaspora / Diaspora Client", + "path": "diaspora-client", + "path_with_namespace": "diaspora/diaspora-client", + "issues_enabled": true, + "merge_requests_enabled": true, + "builds_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "created_at": "2013-09-30T13: 46: 02Z", + "last_activity_at": "2013-09-30T13: 46: 02Z", + "creator_id": 3, + "namespace": { + "created_at": "2013-09-30T13: 46: 02Z", + "description": "", + "id": 3, + "name": "Diaspora", + "owner_id": 1, + "path": "diaspora", + "updated_at": "2013-09-30T13: 46: 02Z" + }, + "archived": false, + "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png" + } +] diff --git a/spec/fixtures/group_search.json b/spec/fixtures/group_search.json new file mode 100644 index 0000000..e6b4daa --- /dev/null +++ b/spec/fixtures/group_search.json @@ -0,0 +1,2 @@ +[{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6} +] diff --git a/spec/fixtures/groups.json b/spec/fixtures/groups.json new file mode 100644 index 0000000..7d8b426 --- /dev/null +++ b/spec/fixtures/groups.json @@ -0,0 +1,2 @@ +[{"id": 3,"name": "ThreeGroup","path": "threegroup","owner_id": 1},{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6} +] \ No newline at end of file diff --git a/spec/fixtures/issue.json b/spec/fixtures/issue.json new file mode 100644 index 0000000..9f70318 --- /dev/null +++ b/spec/fixtures/issue.json @@ -0,0 +1 @@ +{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"} \ No newline at end of file diff --git a/spec/fixtures/issues.json b/spec/fixtures/issues.json new file mode 100644 index 0000000..62e4cad --- /dev/null +++ b/spec/fixtures/issues.json @@ -0,0 +1 @@ +[{"id":1,"project_id":1,"title":"Culpa eius recusandae suscipit autem distinctio dolorum.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":6,"project_id":2,"title":"Ut in dolorum omnis sed sit aliquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":21,"project_id":1,"title":"Vitae ea aliquam et quo eligendi sapiente voluptatum labore hic nihil culpa.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":26,"project_id":2,"title":"Quo enim est nihil atque placeat voluptas neque eos voluptas.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/spec/fixtures/job.json b/spec/fixtures/job.json new file mode 100644 index 0000000..0207e1f --- /dev/null +++ b/spec/fixtures/job.json @@ -0,0 +1,43 @@ +{ + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.880Z", + "artifacts_file": null, + "finished_at": "2015-12-24T17:54:31.198Z", + "id": 8, + "name": "rubocop", + "pipeline": { + "id": 6, + "ref": "master", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:30.733Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/root", + "website_url": "" + } +} diff --git a/spec/fixtures/job_trace.json b/spec/fixtures/job_trace.json new file mode 100644 index 0000000..bf7e899 --- /dev/null +++ b/spec/fixtures/job_trace.json @@ -0,0 +1 @@ +asdasd diff --git a/spec/fixtures/jobs.json b/spec/fixtures/jobs.json new file mode 100644 index 0000000..5ea084b --- /dev/null +++ b/spec/fixtures/jobs.json @@ -0,0 +1,91 @@ +[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.802Z", + "artifacts_file": { + "filename": "artifacts.zip", + "size": 1000 + }, + "finished_at": "2015-12-24T17:54:27.895Z", + "id": 7, + "name": "teaspoon", + "pipeline": { + "id": 6, + "ref": "master", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:27.722Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/root", + "website_url": "" + } + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.727Z", + "artifacts_file": null, + "finished_at": "2015-12-24T17:54:24.921Z", + "id": 6, + "name": "spinach:other", + "pipeline": { + "id": 6, + "ref": "master", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:24.729Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/root", + "website_url": "" + } + } +] diff --git a/spec/fixtures/key.json b/spec/fixtures/key.json new file mode 100644 index 0000000..6595c8c --- /dev/null +++ b/spec/fixtures/key.json @@ -0,0 +1 @@ +{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"} diff --git a/spec/fixtures/keys.json b/spec/fixtures/keys.json new file mode 100644 index 0000000..d81fca6 --- /dev/null +++ b/spec/fixtures/keys.json @@ -0,0 +1 @@ +[{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"}] diff --git a/spec/fixtures/label.json b/spec/fixtures/label.json new file mode 100644 index 0000000..5308d6b --- /dev/null +++ b/spec/fixtures/label.json @@ -0,0 +1 @@ +{"name": "Backlog", "color": "#DD10AA"} diff --git a/spec/fixtures/labels.json b/spec/fixtures/labels.json new file mode 100644 index 0000000..fb995e3 --- /dev/null +++ b/spec/fixtures/labels.json @@ -0,0 +1 @@ +[{"name": "Backlog", "color": "#DD10AA"},{"name": "Documentation", "color": "#1E80DD"}] diff --git a/spec/fixtures/merge_request.json b/spec/fixtures/merge_request.json new file mode 100644 index 0000000..5278f46 --- /dev/null +++ b/spec/fixtures/merge_request.json @@ -0,0 +1 @@ +{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/spec/fixtures/merge_request_changes.json b/spec/fixtures/merge_request_changes.json new file mode 100644 index 0000000..6a75abf --- /dev/null +++ b/spec/fixtures/merge_request_changes.json @@ -0,0 +1 @@ +{"id":2,"iid":5,"project_id":3,"title":"Uncovered","description":"","state":"opened","created_at":"2015-03-15T23:15:13.292+01:00","updated_at":"2015-03-15T23:15:14.132+01:00","target_branch":"master","source_branch":"uncovered","upvotes":0,"downvotes":0,"author":{"name":"Dominik Sander","username":"dsander","id":1,"state":"active","avatar_url":"https://secure.gravatar.com/avatar/7f01734389dd6730d076ddee04838bd3?s=40\u0026d=identicon"},"assignee":null,"source_project_id":6,"target_project_id":6,"labels":[],"milestone":null,"changes":[{"old_path":"lib/omniauth/builder.rb","new_path":"lib/omniauth/builder.rb","a_mode":"100644","b_mode":"100644","diff":"--- a/lib/omniauth/builder.rb\n+++ b/lib/omniauth/builder.rb\n@@ -7,11 +7,13 @@ module OmniAuth\n else\n @app = app\n super(\u0026block)\n+ two = 1 # woah! uncovered\n @ins \u003c\u003c @app\n end\n end\n \n def rack14?\n+ one = 2 # thats oke!\n Rack.release.split('.')[1].to_i \u003e= 4\n end\n ","new_file":false,"renamed_file":false,"deleted_file":false}]} \ No newline at end of file diff --git a/spec/fixtures/merge_request_closes_issues.json b/spec/fixtures/merge_request_closes_issues.json new file mode 100644 index 0000000..4a12eff --- /dev/null +++ b/spec/fixtures/merge_request_closes_issues.json @@ -0,0 +1 @@ +[{"id":1,"iid":1,"project_id":5,"title":"Merge request 1 issue 1","description":"","state":"opened","created_at":"2017-04-06T08:03:36.163Z","updated_at":"2017-04-06T08:03:57.087Z","labels":[],"milestone":null,"assignee":null,"author":{"name":"John","username":"jdoe","id":1,"state":"active","avatar_url":"","web_url":"https://gitlab.com/jdoe"},"user_notes_count":0,"upvotes":0,"downvotes":0,"due_date":null,"confidential":false,"weight":null,"web_url":"https://gitlab.com/jdoe/milestone_merge_requests_test/issues/1"},{"id":2,"iid":2,"project_id":5,"title":"Merge request 1 issue 2","description":"","state":"opened","created_at":"2017-04-06T08:03:44.023Z","updated_at":"2017-04-06T08:03:44.023Z","labels":[],"milestone":null,"assignee":null,"author":{"name":"John","username":"jdoe","id":426047,"state":"active","avatar_url":"","web_url":"https://gitlab.com/jdoe"},"user_notes_count":0,"upvotes":0,"downvotes":0,"due_date":null,"confidential":false,"weight":null,"web_url":"https://gitlab.com/jdoe/milestone_merge_requests_test/issues/2"}] diff --git a/spec/fixtures/merge_request_comment.json b/spec/fixtures/merge_request_comment.json new file mode 100644 index 0000000..742f333 --- /dev/null +++ b/spec/fixtures/merge_request_comment.json @@ -0,0 +1 @@ +{"note":"Cool Merge Request!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}} \ No newline at end of file diff --git a/spec/fixtures/merge_request_comments.json b/spec/fixtures/merge_request_comments.json new file mode 100644 index 0000000..3b9733e --- /dev/null +++ b/spec/fixtures/merge_request_comments.json @@ -0,0 +1 @@ +[{"note":"this is the 1st comment on the 2merge merge request","author":{"id":11,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}},{"note":"another discussion point on the 2merge request","author":{"id":12,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}}] diff --git a/spec/fixtures/merge_request_commits.json b/spec/fixtures/merge_request_commits.json new file mode 100644 index 0000000..806277d --- /dev/null +++ b/spec/fixtures/merge_request_commits.json @@ -0,0 +1 @@ +[{"id":"a2da7552f26d5b46a6a09bb8b7b066e3a102be7d","short_id":"a2da7552","title": "piyo","author_name":"example","author_email":"example@example.com","created_at":"2015-12-19T18:02:31.000+09:00","message":"fuga"},{"id":"3ce509590f37dbce5b877c3e1c78bd3903493170","short_id":"3ce50959","title":"hoge","author_name":"example","author_email":"example@example.com","created_at":"2015-12-19T17:53:46.000+09:00","message":"Hoge"}] diff --git a/spec/fixtures/merge_requests.json b/spec/fixtures/merge_requests.json new file mode 100644 index 0000000..ea32ac4 --- /dev/null +++ b/spec/fixtures/merge_requests.json @@ -0,0 +1 @@ +[{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}}] diff --git a/spec/fixtures/milestone.json b/spec/fixtures/milestone.json new file mode 100644 index 0000000..94ea3d3 --- /dev/null +++ b/spec/fixtures/milestone.json @@ -0,0 +1 @@ +{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"} \ No newline at end of file diff --git a/spec/fixtures/milestone_issues.json b/spec/fixtures/milestone_issues.json new file mode 100644 index 0000000..32597d0 --- /dev/null +++ b/spec/fixtures/milestone_issues.json @@ -0,0 +1 @@ +[{"id":1,"project_id":3,"title":"Culpa eius recusandae suscipit autem distinctio dolorum.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":6,"project_id":3,"title":"Ut in dolorum omnis sed sit aliquam.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":21,"project_id":3,"title":"Vitae ea aliquam et quo eligendi sapiente voluptatum labore hic nihil culpa.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":26,"project_id":3,"title":"Quo enim est nihil atque placeat voluptas neque eos voluptas.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":{"id": 1},"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/spec/fixtures/milestone_merge_requests.json b/spec/fixtures/milestone_merge_requests.json new file mode 100644 index 0000000..aa01a29 --- /dev/null +++ b/spec/fixtures/milestone_merge_requests.json @@ -0,0 +1 @@ +[{"id":1,"iid":1,"project_id":1,"title":"lorem ipsum","description":"","state":"opened","created_at":"2017-03-24T12:23:53.918Z","updated_at":"2017-03-24T12:23:53.918Z","target_branch":"master","source_branch":"def","upvotes":0,"downvotes":0,"author":{"name":"John Doe","username":"jdoe","id":1,"state":"active","avatar_url":"","web_url":"https://gitlab.com/jdoen"},"assignee":null,"source_project_id":1,"target_project_id":1,"labels":[],"work_in_progress":false,"milestone":{"id":1,"iid":1,"project_id":1,"title":"Test","description":"","state":"active","created_at":"2017-03-24T12:23:00.560Z","updated_at":"2017-03-24T12:23:00.560Z","due_date":null,"start_date":null},"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","sha":"aec123d1775790b2347fdd684b5ba613fdeb994b","merge_commit_sha":null,"user_notes_count":0,"approvals_before_merge":null,"should_remove_source_branch":null,"force_remove_source_branch":false,"squash":false,"web_url":"https://gitlab.com/jdoe/milestone_merge_requests_test/merge_requests/2"},{"id":2,"iid":2,"project_id":1,"title":"ipsum lorem","description":"","state":"opened","created_at":"2017-03-24T12:23:24.662Z","updated_at":"2017-03-24T12:23:33.522Z","target_branch":"master","source_branch":"test1","upvotes":0,"downvotes":0,"author":{"name":"Joren","username":"jdoe","id":1,"state":"active","":"","web_url":"https://gitlab.com/jdoe"},"assignee":null,"source_project_id":1,"target_project_id":1,"labels":[],"work_in_progress":false,"milestone":{"id":1,"iid":1,"project_id":1,"title":"Test","description":"","state":"active","created_at":"2017-03-24T12:23:00.560Z","updated_at":"2017-03-24T12:23:00.560Z","due_date":null,"start_date":null},"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","sha":"3ee44c9b40deddae596f838b97523c6f010fd80d","merge_commit_sha":null,"user_notes_count":0,"approvals_before_merge":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"squash":false,"web_url":"https://gitlab.com/jdoe/milestone_merge_requests_test/merge_requests/1"}] diff --git a/spec/fixtures/milestones.json b/spec/fixtures/milestones.json new file mode 100644 index 0000000..f9e309a --- /dev/null +++ b/spec/fixtures/milestones.json @@ -0,0 +1 @@ +[{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"}] \ No newline at end of file diff --git a/spec/fixtures/namespaces.json b/spec/fixtures/namespaces.json new file mode 100644 index 0000000..ae2538b --- /dev/null +++ b/spec/fixtures/namespaces.json @@ -0,0 +1 @@ +[{"id": 1, "path": "john", "kind": "user"}] diff --git a/spec/fixtures/note.json b/spec/fixtures/note.json new file mode 100644 index 0000000..3f575ae --- /dev/null +++ b/spec/fixtures/note.json @@ -0,0 +1 @@ +{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"} diff --git a/spec/fixtures/notes.json b/spec/fixtures/notes.json new file mode 100644 index 0000000..15c0d8c --- /dev/null +++ b/spec/fixtures/notes.json @@ -0,0 +1 @@ +[{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"},{"id":1207,"body":"I know, right?","author":{"id":1,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"created_at":"2012-11-27T19:58:21Z"}] diff --git a/spec/fixtures/pipeline.json b/spec/fixtures/pipeline.json new file mode 100644 index 0000000..d015a6a --- /dev/null +++ b/spec/fixtures/pipeline.json @@ -0,0 +1,23 @@ +{ + "id": 46, + "status": "success", + "ref": "master", + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-08-11T11:28:34.085Z", + "updated_at": "2016-08-11T11:32:35.169Z", + "started_at": null, + "finished_at": "2016-08-11T11:32:35.145Z", + "committed_at": null, + "duration": null +} \ No newline at end of file diff --git a/spec/fixtures/pipeline_cancel.json b/spec/fixtures/pipeline_cancel.json new file mode 100644 index 0000000..fd3fcba --- /dev/null +++ b/spec/fixtures/pipeline_cancel.json @@ -0,0 +1,23 @@ +{ + "id": 46, + "status": "canceled", + "ref": "master", + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-08-11T11:28:34.085Z", + "updated_at": "2016-08-11T11:32:35.169Z", + "started_at": null, + "finished_at": "2016-08-11T11:32:35.145Z", + "committed_at": null, + "duration": null +} \ No newline at end of file diff --git a/spec/fixtures/pipeline_create.json b/spec/fixtures/pipeline_create.json new file mode 100644 index 0000000..b687baa --- /dev/null +++ b/spec/fixtures/pipeline_create.json @@ -0,0 +1,23 @@ +{ + "id": 61, + "sha": "384c444e840a515b23f21915ee5766b87068a70d", + "ref": "master", + "status": "pending", + "before_sha": "0000000000000000000000000000000000000000", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-11-04T09:36:13.747Z", + "updated_at": "2016-11-04T09:36:13.977Z", + "started_at": null, + "finished_at": null, + "committed_at": null, + "duration": null +} \ No newline at end of file diff --git a/spec/fixtures/pipeline_jobs.json b/spec/fixtures/pipeline_jobs.json new file mode 100644 index 0000000..5ea084b --- /dev/null +++ b/spec/fixtures/pipeline_jobs.json @@ -0,0 +1,91 @@ +[ + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.802Z", + "artifacts_file": { + "filename": "artifacts.zip", + "size": 1000 + }, + "finished_at": "2015-12-24T17:54:27.895Z", + "id": 7, + "name": "teaspoon", + "pipeline": { + "id": 6, + "ref": "master", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:27.722Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/root", + "website_url": "" + } + }, + { + "commit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." + }, + "coverage": null, + "created_at": "2015-12-24T15:51:21.727Z", + "artifacts_file": null, + "finished_at": "2015-12-24T17:54:24.921Z", + "id": 6, + "name": "spinach:other", + "pipeline": { + "id": 6, + "ref": "master", + "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "status": "pending" + }, + "ref": "master", + "runner": null, + "stage": "test", + "started_at": "2015-12-24T17:54:24.729Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "created_at": "2015-12-21T13:14:24.077Z", + "id": 1, + "linkedin": "", + "name": "Administrator", + "skype": "", + "state": "active", + "twitter": "", + "username": "root", + "web_url": "http://gitlab.dev/root", + "website_url": "" + } + } +] diff --git a/spec/fixtures/pipeline_retry.json b/spec/fixtures/pipeline_retry.json new file mode 100644 index 0000000..6fcd1ae --- /dev/null +++ b/spec/fixtures/pipeline_retry.json @@ -0,0 +1,23 @@ +{ + "id": 46, + "status": "pending", + "ref": "master", + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-08-11T11:28:34.085Z", + "updated_at": "2016-08-11T11:32:35.169Z", + "started_at": null, + "finished_at": "2016-08-11T11:32:35.145Z", + "committed_at": null, + "duration": null +} \ No newline at end of file diff --git a/spec/fixtures/pipelines.json b/spec/fixtures/pipelines.json new file mode 100644 index 0000000..c5bd396 --- /dev/null +++ b/spec/fixtures/pipelines.json @@ -0,0 +1,48 @@ +[ + { + "id": 47, + "status": "pending", + "ref": "new-pipeline", + "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "before_sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-08-16T10:23:19.007Z", + "updated_at": "2016-08-16T10:23:19.216Z", + "started_at": null, + "finished_at": null, + "committed_at": null, + "duration": null + }, + { + "id": 48, + "status": "pending", + "ref": "new-pipeline", + "sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", + "before_sha": "eb94b618fb5865b26e80fdd8ae531b7a63ad851a", + "tag": false, + "yaml_errors": null, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://localhost:3000/root" + }, + "created_at": "2016-08-16T10:23:21.184Z", + "updated_at": "2016-08-16T10:23:21.314Z", + "started_at": null, + "finished_at": null, + "committed_at": null, + "duration": null + } +] \ No newline at end of file diff --git a/spec/fixtures/project.json b/spec/fixtures/project.json new file mode 100644 index 0000000..1f4f960 --- /dev/null +++ b/spec/fixtures/project.json @@ -0,0 +1 @@ +{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"public":false,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"} \ No newline at end of file diff --git a/spec/fixtures/project_commit.json b/spec/fixtures/project_commit.json new file mode 100644 index 0000000..ace52b7 --- /dev/null +++ b/spec/fixtures/project_commit.json @@ -0,0 +1,13 @@ +{ + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2012-09-20T09:06:12+03:00", + "committed_date": "2012-09-20T09:06:12+03:00", + "authored_date": "2012-09-20T09:06:12+03:00", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ] +} diff --git a/spec/fixtures/project_commit_comment.json b/spec/fixtures/project_commit_comment.json new file mode 100644 index 0000000..d1cdd90 --- /dev/null +++ b/spec/fixtures/project_commit_comment.json @@ -0,0 +1 @@ +{"note":"Nice code!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}} diff --git a/spec/fixtures/project_commit_comments.json b/spec/fixtures/project_commit_comments.json new file mode 100644 index 0000000..6690e29 --- /dev/null +++ b/spec/fixtures/project_commit_comments.json @@ -0,0 +1 @@ +[{"note":"this is the 1st comment on commit 6104942438c14ec7bd21c6cd5bd995272b3faff6","author":{"id":11,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}},{"note":"another discussion point on commit 6104942438c14ec7bd21c6cd5bd995272b3faff6","author":{"id":12,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}}] diff --git a/spec/fixtures/project_commit_create.json b/spec/fixtures/project_commit_create.json new file mode 100644 index 0000000..a0fae22 --- /dev/null +++ b/spec/fixtures/project_commit_create.json @@ -0,0 +1,22 @@ +{ + "id": "ed899a2f4b50b4370feeea94676502b42383c746", + "short_id": "ed899a2f4b5", + "title": "some commit message", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dzaporozhets@sphereconsultinginc.com", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dzaporozhets@sphereconsultinginc.com", + "created_at": "2016-09-20T09:26:24.000-07:00", + "message": "some commit message", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ], + "committed_date": "2016-09-20T09:26:24.000-07:00", + "authored_date": "2016-09-20T09:26:24.000-07:00", + "stats": { + "additions": 2, + "deletions": 2, + "total": 4 + }, + "status": null +} \ No newline at end of file diff --git a/spec/fixtures/project_commit_diff.json b/spec/fixtures/project_commit_diff.json new file mode 100644 index 0000000..ad3dfde --- /dev/null +++ b/spec/fixtures/project_commit_diff.json @@ -0,0 +1,10 @@ +{ + "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", + "new_path": "doc/update/5.4-to-6.0.md", + "old_path": "doc/update/5.4-to-6.0.md", + "a_mode": null, + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false +} diff --git a/spec/fixtures/project_commit_status.json b/spec/fixtures/project_commit_status.json new file mode 100644 index 0000000..4b852f8 --- /dev/null +++ b/spec/fixtures/project_commit_status.json @@ -0,0 +1,42 @@ +[ + { + "id": 496, + "sha": "7d938cb8ac15788d71f4b67c035515a160ea76d8", + "ref": "decreased-spec", + "status": "failed", + "name": "test", + "target_url": null, + "description": null, + "created_at": "2015-10-23T23:35:48.693+02:00", + "started_at": null, + "finished_at": "2015-10-23T23:35:48.716+02:00", + "author": { + "name": "Dominik Sander", + "username": "dsander", + "id": 1, + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/xxxxx?s=40&d=identicon", + "web_url": "https://github.com/u/dsander" + } + }, + { + "id": 493, + "sha": "7d938cb8ac15788d71f4b67c035515a160ea76d8", + "ref": "decreased-spec", + "status": "success", + "name": "specs", + "target_url": "https://github.com/dsander/omniauth/builds/493", + "description": null, + "created_at": "2015-10-23T21:39:19.384+02:00", + "started_at": "2015-10-23T21:39:21.900+02:00", + "finished_at": "2015-10-23T21:39:35.215+02:00", + "author": { + "name": "Dominik Sander", + "username": "dsander", + "id": 1, + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/xxxxx?s=40&d=identicon", + "web_url": "https://github.com/u/dsander" + } + } +] \ No newline at end of file diff --git a/spec/fixtures/project_commits.json b/spec/fixtures/project_commits.json new file mode 100644 index 0000000..58cb502 --- /dev/null +++ b/spec/fixtures/project_commits.json @@ -0,0 +1 @@ +[{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","short_id":"f7dd067490f","title":"API: expose issues project id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T04:22:21-07:00"},{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616","short_id":"949b1df930b","title":"API: update docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:35:41-07:00"},{"id":"1b95c8bff351f6718ec31ac1de1e48c57bc95d44","short_id":"1b95c8bff35","title":"API: ability to get project by id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:18:30-07:00"},{"id":"92d98f5a0c28bffd7b070cda190b07ab72667d58","short_id":"92d98f5a0c2","title":"Merge pull request #1118 from patthoyts/pt/ldap-missing-password","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:51:06-07:00"},{"id":"60d3e94874964a626f105d3598e1c122addcf43e","short_id":"60d3e948749","title":"Merge pull request #1122 from patthoyts/pt/missing-log","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:50:34-07:00"},{"id":"b683a71aa1230f17f9df47661c77dfeae27027de","short_id":"b683a71aa12","title":"Merge pull request #1135 from NARKOZ/api","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:48:00-07:00"},{"id":"fbb41100db35cf2def2c8b4d896b7015d56bd15b","short_id":"fbb41100db3","title":"update help section with issues API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:52:43-07:00"},{"id":"eca823c1c7cef45cc18c6ab36d2327650c85bfc3","short_id":"eca823c1c7c","title":"Merge branch 'master' into api","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:46:36-07:00"},{"id":"024e0348904179a8dea81c01e27a5f014cf57499","short_id":"024e0348904","title":"update API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:25:01-07:00"},{"id":"7b33d8cbcab3b0ee5789ec607455ab62130db69f","short_id":"7b33d8cbcab","title":"add issues API","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:19:51-07:00"},{"id":"6035ad7e1fe519d0c6a42731790183889e3ba31d","short_id":"6035ad7e1fe","title":"Create the githost.log file if necessary.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T07:32:04-07:00"},{"id":"a2d244ec062f3348f6cd1c5218c6097402c5f562","short_id":"a2d244ec062","title":"Handle LDAP missing credentials error with a flash message.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T01:04:05-07:00"},{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","short_id":"8b7e404b5b6","title":"Up to 2.7.0","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:53:55-07:00"},{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5","short_id":"11721b0dbe8","title":"Help section for system hooks completed","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:47:57-07:00"},{"id":"9c8a1e651716212cf50a623d98e03b8dbdb2c64a","short_id":"9c8a1e65171","title":"Fix system hook example","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:32:42-07:00"},{"id":"4261acda90ff4c61326d80cba026ae76e8551f8f","short_id":"4261acda90f","title":"move SSH keys tab closer to begining","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:27:09-07:00"},{"id":"a69fc5dd23bd502fd36892a80eec21a4c53891f8","short_id":"a69fc5dd23b","title":"Endless event loading for dsahboard","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:23:05-07:00"},{"id":"860fa1163a5fbdfec2bb01ff2d584351554dee29","short_id":"860fa1163a5","title":"Merge pull request #1117 from patthoyts/pt/user-form","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T14:23:49-07:00"},{"id":"787e5e94acf5e20280416c9fda105ef5b77576b3","short_id":"787e5e94acf","title":"Fix english on the edit user form.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-20T14:18:42-07:00"},{"id":"9267cb04b0b3fdf127899c4b7e636dc27fac06d3","short_id":"9267cb04b0b","title":"Merge branch 'refactoring_controllers' of dev.gitlabhq.com:gitlabhq","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T07:24:56-07:00"}] \ No newline at end of file diff --git a/spec/fixtures/project_edit.json b/spec/fixtures/project_edit.json new file mode 100644 index 0000000..b5b8d28 --- /dev/null +++ b/spec/fixtures/project_edit.json @@ -0,0 +1,21 @@ +{ + "id":3, + "code":"gitlab", + "name":"Gitlab-edit", + "description":null, + "path":"gitlab", + "default_branch":null, + "owner":{ + "id":1, + "email":"john@example.com", + "name":"John Smith", + "blocked":false, + "created_at":"2012-09-17T09:41:56Z" + }, + "public":false, + "issues_enabled":true, + "merge_requests_enabled":true, + "wall_enabled":true, + "wiki_enabled":true, + "created_at":"2012-09-17T09:41:58Z" +} diff --git a/spec/fixtures/project_events.json b/spec/fixtures/project_events.json new file mode 100644 index 0000000..4d5afc0 --- /dev/null +++ b/spec/fixtures/project_events.json @@ -0,0 +1 @@ +[{"title":null,"project_id":2,"action_name":"opened","target_id":null,"target_type":null,"author_id":1,"data":{"before":"ac0c1aa3898d6dea54d7868ea6f9c45fd5e30c59","after":"66350dbb62a221bc619b665aef3e1e7d3b306747","ref":"refs/heads/master","user_id":1,"user_name":"Administrator","project_id":2,"repository":{"name":"gitlab-ci","url":"git@demo.gitlab.com:gitlab/gitlab-ci.git","description":"Continuous integration server for gitlabhq | Coordinator","homepage":"http://demo.gitlab.com/gitlab/gitlab-ci"},"commits":[{"id":"8cf469b039931bab37bbf025e6b69287ea3cfb0e","message":"Modify screenshot\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:34:27+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/8cf469b039931bab37bbf025e6b69287ea3cfb0e","author":{"name":"Dummy","email":"dummy@gmail.com"}},{"id":"66350dbb62a221bc619b665aef3e1e7d3b306747","message":"Edit some code\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:35:15+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/66350dbb62a221bc619b665aef3e1e7d3b306747","author":{"name":"Dummy","email":"dummy@gmail.com"}}],"total_commits_count":2},"target_title":null,"created_at":"2014-05-20T10:35:26.240Z"},{"title":null,"project_id":2,"action_name":"opened","target_id":2,"target_type":"MergeRequest","author_id":1,"data":null,"target_title":" Morbi et cursus leo. Sed eget vestibulum sapien","created_at":"2014-05-20T10:24:11.917Z"}] diff --git a/spec/fixtures/project_for_user.json b/spec/fixtures/project_for_user.json new file mode 100644 index 0000000..e2835d8 --- /dev/null +++ b/spec/fixtures/project_for_user.json @@ -0,0 +1 @@ +{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Owner","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"} diff --git a/spec/fixtures/project_fork.json b/spec/fixtures/project_fork.json new file mode 100644 index 0000000..f87d687 --- /dev/null +++ b/spec/fixtures/project_fork.json @@ -0,0 +1,50 @@ +{ + "id":20, + "description":"desc", + "default_branch":"master", + "tag_list":[ + + ], + "public":false, + "archived":false, + "visibility_level":10, + "ssh_url_to_repo":"git@git.gitlab.com:root/gitlab.git", + "http_url_to_repo":"http://git.gitlab.com/root/gitlab.git", + "web_url":"http://git.gitlab.com/root/gitlab", + "owner":{ + "name":"Administrator", + "username":"root", + "id":1, + "state":"active", + "avatar_url":"http://git.gitlab.com/uploads/user/avatar/1/12586377.jpeg" + }, + "name":"gitlab", + "name_with_namespace":"Administrator / gitlab", + "path":"gitlab", + "path_with_namespace":"root/gitlab", + "issues_enabled":true, + "merge_requests_enabled":true, + "wiki_enabled":true, + "snippets_enabled":false, + "created_at":"2015-06-08T01:29:17.190Z", + "last_activity_at":"2015-06-08T01:29:17.190Z", + "creator_id":1, + "namespace":{ + "id":1, + "name":"root", + "path":"root", + "owner_id":1, + "created_at":"2015-05-28T19:23:40.445Z", + "updated_at":"2015-05-28T19:23:40.445Z", + "description":"", + "avatar":null + }, + "forked_from_project":{ + "id":3, + "name":"Gitlab", + "name_with_namespace":"Root / gitlab", + "path":"gitlab", + "path_with_namespace":"root/gitlab" + }, + "avatar_url":null +} diff --git a/spec/fixtures/project_fork_link.json b/spec/fixtures/project_fork_link.json new file mode 100644 index 0000000..f1490df --- /dev/null +++ b/spec/fixtures/project_fork_link.json @@ -0,0 +1 @@ +{"created_at":"2013-07-03T13:51:48Z","forked_from_project_id":24,"forked_to_project_id":42,"id":1,"updated_at":"2013-07-03T13:51:48Z"} \ No newline at end of file diff --git a/spec/fixtures/project_forked_for_user.json b/spec/fixtures/project_forked_for_user.json new file mode 100644 index 0000000..254c517 --- /dev/null +++ b/spec/fixtures/project_forked_for_user.json @@ -0,0 +1,50 @@ +{ + "id":20, + "description":"desc", + "default_branch":"master", + "tag_list":[ + + ], + "public":false, + "archived":false, + "visibility_level":10, + "ssh_url_to_repo":"git@git.gitlab.com:root/gitlab.git", + "http_url_to_repo":"http://git.gitlab.com/root/gitlab.git", + "web_url":"http://git.gitlab.com/root/gitlab", + "owner":{ + "name":"Jack Smith", + "username":"jack.smith", + "id":2, + "state":"active", + "avatar_url":"http://git.gitlab.com/uploads/user/avatar/1/12586377.jpeg" + }, + "name":"gitlab", + "name_with_namespace":"Jack Smith / gitlab", + "path":"gitlab", + "path_with_namespace":"jack.smith/gitlab", + "issues_enabled":true, + "merge_requests_enabled":true, + "wiki_enabled":true, + "snippets_enabled":false, + "created_at":"2015-06-08T01:29:17.190Z", + "last_activity_at":"2015-06-08T01:29:17.190Z", + "creator_id":1, + "namespace":{ + "id":1, + "name":"jack.smith", + "path":"jack.smith", + "owner_id":2, + "created_at":"2015-05-28T19:23:40.445Z", + "updated_at":"2015-05-28T19:23:40.445Z", + "description":"", + "avatar":null + }, + "forked_from_project":{ + "id":3, + "name":"Gitlab", + "name_with_namespace":"Root / gitlab", + "path":"gitlab", + "path_with_namespace":"root/gitlab" + }, + "avatar_url":null +} diff --git a/spec/fixtures/project_hook.json b/spec/fixtures/project_hook.json new file mode 100644 index 0000000..180dd45 --- /dev/null +++ b/spec/fixtures/project_hook.json @@ -0,0 +1 @@ +{"id":1,"url":"https://api.example.net/v1/webhooks/ci"} diff --git a/spec/fixtures/project_hooks.json b/spec/fixtures/project_hooks.json new file mode 100644 index 0000000..e70d412 --- /dev/null +++ b/spec/fixtures/project_hooks.json @@ -0,0 +1 @@ +[{"id":1,"url":"https://api.example.net/v1/webhooks/ci"}] \ No newline at end of file diff --git a/spec/fixtures/project_issues.json b/spec/fixtures/project_issues.json new file mode 100644 index 0000000..87fb2fb --- /dev/null +++ b/spec/fixtures/project_issues.json @@ -0,0 +1 @@ +[{"id":36,"project_id":3,"title":"Eos ut modi et laudantium quasi porro voluptas sed.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":35,"project_id":3,"title":"Ducimus illo in iure voluptatem dolores labore.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":34,"project_id":3,"title":"Rem tempora voluptatum atque eum sit nihil neque.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":16,"project_id":3,"title":"Numquam earum aut laudantium reprehenderit voluptatem aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":15,"project_id":3,"title":"Qui veritatis voluptas fuga voluptate voluptas cupiditate.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":14,"project_id":3,"title":"In assumenda et ipsa qui debitis voluptatem incidunt.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":13,"project_id":3,"title":"Illo eveniet consequatur enim iste provident facilis rerum voluptatem et architecto aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/spec/fixtures/project_key.json b/spec/fixtures/project_key.json new file mode 100644 index 0000000..d917f94 --- /dev/null +++ b/spec/fixtures/project_key.json @@ -0,0 +1,6 @@ +{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +} \ No newline at end of file diff --git a/spec/fixtures/project_keys.json b/spec/fixtures/project_keys.json new file mode 100644 index 0000000..dd22f96 --- /dev/null +++ b/spec/fixtures/project_keys.json @@ -0,0 +1,6 @@ +[{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +}] \ No newline at end of file diff --git a/spec/fixtures/project_runner_enable.json b/spec/fixtures/project_runner_enable.json new file mode 100644 index 0000000..60c5326 --- /dev/null +++ b/spec/fixtures/project_runner_enable.json @@ -0,0 +1,7 @@ +{ + "active": true, + "description": "test-2016-02-01", + "id": 9, + "is_shared": false, + "name": null +} diff --git a/spec/fixtures/project_runners.json b/spec/fixtures/project_runners.json new file mode 100644 index 0000000..f043a2c --- /dev/null +++ b/spec/fixtures/project_runners.json @@ -0,0 +1,16 @@ +[ + { + "active": true, + "description": "test-2-20150125", + "id": 8, + "is_shared": false, + "name": null + }, + { + "active": true, + "description": "development_runner", + "id": 5, + "is_shared": true, + "name": null + } +] diff --git a/spec/fixtures/project_search.json b/spec/fixtures/project_search.json new file mode 100644 index 0000000..80fd4af --- /dev/null +++ b/spec/fixtures/project_search.json @@ -0,0 +1 @@ +[{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"}] diff --git a/spec/fixtures/project_star.json b/spec/fixtures/project_star.json new file mode 100644 index 0000000..4e932f7 --- /dev/null +++ b/spec/fixtures/project_star.json @@ -0,0 +1,44 @@ +{ + "id": 3, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 10, + "ssh_url_to_repo":"git@git.gitlab.com:root/gitlab.git", + "http_url_to_repo":"http://git.gitlab.com/root/gitlab.git", + "web_url":"http://git.gitlab.com/root/gitlab", + "tag_list": [ + + ], + "name": "GitLab Community Edition", + "name_with_namespace": "GitLab / GitLab Community Edition", + "path": "gitlab-ce", + "path_with_namespace": "gitlab/gitlab-ce", + "issues_enabled": true, + "open_issues_count": 1, + "merge_requests_enabled": true, + "builds_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": false, + "created_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "creator_id": 3, + "namespace": { + "created_at": "2013-09-30T13:46:02Z", + "description": "", + "id": 3, + "name": "GitLab", + "owner_id": 1, + "path": "gitlab", + "updated_at": "2013-09-30T13:46:02Z" + }, + "archived": true, + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 1, + "public_builds": true, + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false +} diff --git a/spec/fixtures/project_tag_annotated.json b/spec/fixtures/project_tag_annotated.json new file mode 100644 index 0000000..3bd2070 --- /dev/null +++ b/spec/fixtures/project_tag_annotated.json @@ -0,0 +1 @@ +{"name": "v1.1.0","message": "Release 1.1.0","commit": {"id": "2695effb5807a22ff3d138d593fd856244e155e7","parents": [],"message": "Initial commit","authored_date": "2012-05-28T04:42:42-07:00","author_name": "John Smith","author email": "john@example.com","committer_name": "Jack Smith","committed_date": "2012-05-28T04:42:42-07:00","committer_email": "jack@example.com"}} diff --git a/spec/fixtures/project_tag_lightweight.json b/spec/fixtures/project_tag_lightweight.json new file mode 100644 index 0000000..cec1381 --- /dev/null +++ b/spec/fixtures/project_tag_lightweight.json @@ -0,0 +1 @@ +{"name": "v1.0.0","message": null,"commit": {"id": "2695effb5807a22ff3d138d593fd856244e155e7","parents": [],"message": "Initial commit","authored_date": "2012-05-28T04:42:42-07:00","author_name": "John Smith","author email": "john@example.com","committer_name": "Jack Smith","committed_date": "2012-05-28T04:42:42-07:00","committer_email": "jack@example.com"}} diff --git a/spec/fixtures/project_tags.json b/spec/fixtures/project_tags.json new file mode 100644 index 0000000..1e2fb96 --- /dev/null +++ b/spec/fixtures/project_tags.json @@ -0,0 +1 @@ +[{"name":"v2.8.2","commit":{"id":"a502f67c0b358cc6b391df0c5dca48375c21fcad","parents":[{"id":"4381084af341684240b1a671d368511afcf5774a"}],"tree":"1612068bdd20de5d14b3096cfa4c621e2051ed4c","message":"Up to 2.8.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-24T02:03:48-07:00","committed_date":"2012-08-24T02:03:48-07:00"}},{"name":"v2.8.1","commit":{"id":"ed2b53cd1c34c421b23208eeb502a141a6829f9d","parents":[{"id":"7ab587a47791e371f5c109c14097a5d1d7776ea5"}],"tree":"b7393b0b33b777583b285e85b423c4e5ab7f859f","message":"Up to 2.8.1","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-22T23:17:18-07:00","committed_date":"2012-08-22T23:17:18-07:00"}},{"name":"v2.8.0pre","commit":{"id":"b2c6ba97a25d299e83c51493d7bc770c13b8ed1a","parents":[{"id":"05da3801f53f06fdc529b4f3820af1380039f245"},{"id":"66399d558da45fb9cd3ea972a47a4f7bb12bfc8d"}],"tree":"36ad53f35bce1fe3f2a4a5f840e7b1bdbfed9c82","message":"Merge pull request #1230 from tsigo/hooray_apostrophes\n\nCorrect usage of \"Can't\"","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-16T14:11:08-07:00","committed_date":"2012-08-16T14:11:08-07:00"}},{"name":"v2.8.0","commit":{"id":"5c7ed6fa26b47ac71ff6ba04720d85df6d74b200","parents":[{"id":"d1daeba1736ba145fe525ce08a91f29495a3abf1"}],"tree":"4fc230ff2dbc0e75f27321eac2976aba5a6d323d","message":"Up to 2.8","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-21T15:15:26-07:00","committed_date":"2012-08-21T15:15:26-07:00"}},{"name":"v2.7.0pre","commit":{"id":"72a571724d84d112f98a5543c971e9b3b9da1383","parents":[{"id":"3ac840ff06e0ee5b349c52b5a8c02e803a17eec3"},{"id":"990b9217d9a55e26a53d4143d4a3c89123384327"}],"tree":"64b104df5d956e21e0749dc8e70849d1989de36f","message":"Merge pull request #1096 from moregeek/show-flash-note-when-destroying-a-project\n\nshow flash notice after deletion of a project","author":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"committer":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"authored_date":"2012-07-18T05:35:42-07:00","committed_date":"2012-07-18T05:35:42-07:00"}},{"name":"v2.7.0","commit":{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","parents":[{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5"}],"tree":"89fe8c5ff58daaedea07a910cffb14b04ebcc828","message":"Up to 2.7.0","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-07-21T00:53:55-07:00","committed_date":"2012-07-21T00:53:55-07:00"}},{"name":"v2.6.3","commit":{"id":"666cdb22792dd955a286b9993d6235b4cdd68b4b","parents":[{"id":"d92446df1fdba87101c92c90b1c34eb2f1eebef4"}],"tree":"888173aa4c12a4920d318c35b950095d3505673d","message":"up to 2.6.3","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-26T09:20:47-07:00","committed_date":"2012-06-26T09:21:28-07:00"}},{"name":"v2.6.2","commit":{"id":"39fecb554f172a0c8ea00316e612e1d37efc7200","parents":[{"id":"68389588d664100590b1a6ca7eedd50860b7e9bc"}],"tree":"53accb25e0b9d038d550cf387753bde15fe4ad19","message":"Up to 2.6.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T13:50:58-07:00","committed_date":"2012-06-22T13:50:58-07:00"}},{"name":"v2.6.1","commit":{"id":"d92a22c9e627268eca697bbd9b660d8c335df953","parents":[{"id":"193804516b8b0783c850981456e947f888ff51bb"}],"tree":"4ac1b5225f597ab55372cb5e950b121d6f55e386","message":"Up to 2.6.1","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T12:49:03-07:00","committed_date":"2012-06-22T12:49:03-07:00"}},{"name":"v2.6.0","commit":{"id":"b32465712becfbcf83d63b1e6eff7d1483fdabea","parents":[{"id":"1903f6ade027df0f10ef96b9439495eeda07482c"}],"tree":"ffbc05fd0f1771c1602c956df9556260048c7167","message":"Up to 2.6","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-21T10:25:23-07:00","committed_date":"2012-06-21T10:25:23-07:00"}},{"name":"v2.5.0","commit":{"id":"cc8369144db2147d2956e8dd7d314e9a7dfd4fbb","parents":[{"id":"1b2068eaa91e5002d01a220c65da21dad8ccb071"}],"tree":"666a442e00689911169e8cc336c5ce60d014854c","message":"Prevent app crash in case if encoding failed","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-22T04:57:04-07:00","committed_date":"2012-05-22T04:57:04-07:00"}},{"name":"v2.4.2","commit":{"id":"f18339c26d673c5f8b4c19776036fd42a0de30aa","parents":[{"id":"c937d06c3c98e9ffce8ec1132203eaff6bf7b231"},{"id":"35e602f19c83585d64aa2043ed26eeb8cd7b40e2"}],"tree":"5101f0cd8e395fee1996764298a202437757e85b","message":"Merge branch 'master' of github.com:gitlabhq/gitlabhq","author":{"name":"Zevs","email":"vsv2711@gmail.com"},"committer":{"name":"Zevs","email":"vsv2711@gmail.com"},"authored_date":"2012-04-29T14:24:59-07:00","committed_date":"2012-04-29T14:24:59-07:00"}},{"name":"v2.4.1","commit":{"id":"d97a9aa4a44ff9f452144fad348fd9d7e3b48260","parents":[{"id":"21f3da23589d50038728393f0badc6255b5762ca"}],"tree":"905c33874b064778199f806749d5688e33d64be3","message":"fixed email markdown","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2012-04-23T05:32:56-07:00","committed_date":"2012-04-23T05:32:56-07:00"}},{"name":"v2.4.0pre","commit":{"id":"1845429268364e75bffdeb1075de8f1606e157ec","parents":[{"id":"45b18365d5f409f196a02a4e6e2b77b8ebef909b"}],"tree":"423c70246fa7ffd8804b26628fea34bdb2b22846","message":"Use try for commit prev_commit_id detection","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-19T13:35:35-07:00","committed_date":"2012-04-19T13:35:35-07:00"}},{"name":"v2.4.0","commit":{"id":"204c66461ed519eb0078be7e8ac8a6cb56834753","parents":[{"id":"511d07c47c9bf3a18bfa276d452c899369432a22"}],"tree":"9416c777cccf87d348f5705078e82f3f97485e19","message":"corrected exception for automerge","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-22T06:49:45-07:00","committed_date":"2012-04-22T06:49:45-07:00"}},{"name":"v2.3.1","commit":{"id":"fa8219e0a753e642a6f1dbdfc010d01ae8a949ee","parents":[{"id":"81da8e46f24913ccf42d3e2644962cbcbc0f9c2e"}],"tree":"5debfcd6d17f9d582aace6ac9b80db27d5c1fe36","message":"better MR list, dashboard pollished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-22T13:57:04-07:00","committed_date":"2012-03-22T13:57:04-07:00"}},{"name":"v2.3.0pre","commit":{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d","parents":[{"id":"724ea16c348bc61cf7cb3dbe362c6f30cff1b2c7"}],"tree":"6f4c22761fd2dee405d3fbf38f9dd835bb3c8694","message":"Merged activities & projects pages","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-19T15:05:35-07:00","committed_date":"2012-03-19T15:05:35-07:00"}},{"name":"v2.3.0","commit":{"id":"b57faf9282d7df6cdd62953d474652a0ae2e6896","parents":[{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d"}],"tree":"f0d5b826df373191b4681452fc2ae4c5970cef4a","message":"Push events polished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-20T14:59:35-07:00","committed_date":"2012-03-20T14:59:35-07:00"}},{"name":"v2.2.0pre","commit":{"id":"6a445b42003007cbb6c06f477c4d7a0b175688c1","parents":[{"id":"22f4c1908d0fc2dbce02e74ed03bf65f028d78d6"}],"tree":"9c60577833f6ca717acdebfa66140124c88e8471","message":"fixed forgot password form","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-20T10:37:37-08:00","committed_date":"2012-02-20T10:37:37-08:00"}},{"name":"v2.2.0","commit":{"id":"9e6d0710e927aa8ea834b8a9ae9f277be617ac7d","parents":[{"id":"8c40aab120dbc5507ab9cc8d7ad8e2519d6e9f25"},{"id":"6ea87c47f0f8a24ae031c3fff17bc913889ecd00"}],"tree":"86c831ab21236f21ffa5b97c752369612ce41b39","message":"Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff\n\nIncorrect line numbering in diff","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-22T07:14:54-08:00","committed_date":"2012-02-22T07:14:54-08:00"}},{"name":"v2.1.0","commit":{"id":"98d6492582d232ed86525aa31ccbf280f4cbdaef","parents":[{"id":"611c5a87ab0c083a43785323b09cc47f554c3ba4"}],"tree":"1689b3cad580a18fd9b429ee0b33dac21c9f5a48","message":"removed broken migration","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-01-22T10:52:06-08:00","committed_date":"2012-01-22T10:52:06-08:00"}},{"name":"v2.0.0","commit":{"id":"9a2a8612769d472503b367fa35e99f6fb2876704","parents":[{"id":"2f7b67161952fc9ab322eba6878511b5f2dd5cf1"}],"tree":"26cdb4e66b5e664fe4bcd57d011c54c9c9c26ded","message":"Design tab for profile. Colorscheme as db value","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-12-20T12:47:09-08:00","committed_date":"2011-12-20T12:47:09-08:00"}},{"name":"v1.2.2","commit":{"id":"139a332293b9d8c4e5436619036e093483d8347f","parents":[{"id":"ade12da9488bea19d12505c371ead35686a1436e"}],"tree":"365d57f4df5c5dcac69b666cf6d2bfd8ef058008","message":"updated readme","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-25T14:30:51-08:00","committed_date":"2011-11-25T14:30:51-08:00"}},{"name":"v1.2.1","commit":{"id":"7ebba27db21719c0035bab65fea92a4780051c73","parents":[{"id":"b56024100d40457a998f83adae3cdc830c997cda"},{"id":"a4fbe13fce87cb6ff2a27a2574ae25bf1dad145c"}],"tree":"b121a7576af1503a96954ce9a94598a68579e053","message":"Merge branch 'master' of dev.gitlabhq.com:gitlabhq","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T13:15:09-08:00","committed_date":"2011-11-22T13:15:09-08:00"}},{"name":"v1.2.0pre","commit":{"id":"86829cae50857b5edf74b935380c6f68a19c2282","parents":[{"id":"a6b99319381c2d62ec4b92d64805e8de8965859e"}],"tree":"6aab9d13000584fa96fb3cb34d94f3b122bd1143","message":"fixed min height for menu","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2011-11-22T06:03:27-08:00","committed_date":"2011-11-22T06:03:27-08:00"}},{"name":"v1.2.0","commit":{"id":"b56024100d40457a998f83adae3cdc830c997cda","parents":[{"id":"4451b8df8ad6d4b6d79fbce77687c6c2fd37d0a9"}],"tree":"f402cbb6d54526a32b30968c98410bae97b27c8d","message":"lil style fixes","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T09:57:25-08:00","committed_date":"2011-11-22T09:57:25-08:00"}},{"name":"v1.1.0pre","commit":{"id":"6b030fd41d697e327d2935b406cba70b6a460504","parents":[{"id":"3a2b273316fb29d63b489906f85d9b5329377258"}],"tree":"63b1fdb2a0f135f7074f6a94da14543b8450dd71","message":"1.1pre1","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-21T10:04:41-07:00","committed_date":"2011-10-21T10:04:41-07:00"}},{"name":"v1.1.0","commit":{"id":"ba8048d71019b5aaa1f92ee5c3415bfddaa9babb","parents":[{"id":"6b030fd41d697e327d2935b406cba70b6a460504"}],"tree":"4db2b5f4f9b374dd1be3579459bc5947c225c9ba","message":"v1.1.0","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-22T06:07:26-07:00","committed_date":"2011-10-22T06:07:26-07:00"}},{"name":"v1.0.2","commit":{"id":"3a2b273316fb29d63b489906f85d9b5329377258","parents":[{"id":"757ea634665e475bf69c1ec962040a0511ee8aeb"},{"id":"c374eb80ff9fb71d37faffc15714bf98b632d3e5"}],"tree":"e0d8170e61a9468a7bb5d4e63305171ec1efa6bf","message":"Merge pull request #40 from vslinko/patch-1\n\nIncrease max key length. Some keys has comment after key string.","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-10-18T23:30:06-07:00","committed_date":"2011-10-18T23:30:06-07:00"}},{"name":"v1.0.1","commit":{"id":"7b5799a97998b68416f1b6233ce427135c99165a","parents":[{"id":"0541b3f3c5dcd291d144c83d9731c75ee811b4e0"},{"id":"7b67480c76db8b9a9ccdc80015cc500dc6d26892"}],"tree":"e052185e9dd72a1b1a04d59a5f9efbf3c0369601","message":"Merge branch '1x' of github.com:gitlabhq/gitlabhq into 1x","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-14T15:16:44-07:00","committed_date":"2011-10-14T15:16:44-07:00"}}] \ No newline at end of file diff --git a/spec/fixtures/project_unstar.json b/spec/fixtures/project_unstar.json new file mode 100644 index 0000000..33bc36f --- /dev/null +++ b/spec/fixtures/project_unstar.json @@ -0,0 +1,44 @@ +{ + "id": 3, + "description": null, + "default_branch": "master", + "public": false, + "visibility_level": 10, + "ssh_url_to_repo":"git@git.gitlab.com:root/gitlab.git", + "http_url_to_repo":"http://git.gitlab.com/root/gitlab.git", + "web_url":"http://git.gitlab.com/root/gitlab", + "tag_list": [ + + ], + "name": "GitLab Community Edition", + "name_with_namespace": "GitLab / GitLab Community Edition", + "path": "gitlab-ce", + "path_with_namespace": "gitlab/gitlab-ce", + "issues_enabled": true, + "open_issues_count": 1, + "merge_requests_enabled": true, + "builds_enabled": true, + "wiki_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": false, + "created_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "creator_id": 3, + "namespace": { + "created_at": "2013-09-30T13:46:02Z", + "description": "", + "id": 3, + "name": "GitLab", + "owner_id": 1, + "path": "gitlab", + "updated_at": "2013-09-30T13:46:02Z" + }, + "archived": true, + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "public_builds": true, + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false +} diff --git a/spec/fixtures/project_update_commit_status.json b/spec/fixtures/project_update_commit_status.json new file mode 100644 index 0000000..fd81d18 --- /dev/null +++ b/spec/fixtures/project_update_commit_status.json @@ -0,0 +1,20 @@ +{ + "id": 498, + "sha": "7d938cb8ac15788d71f4b67c035515a160ea76d8", + "ref": "decreased-spec", + "status": "failed", + "name": "test", + "target_url": null, + "description": null, + "created_at": "2015-10-23T23:56:49.499+02:00", + "started_at": null, + "finished_at": "2015-10-23T23:56:49.534+02:00", + "author": { + "name": "Dominik Sander", + "username": "dsander", + "id": 1, + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/xxx?s=40&d=identicon", + "web_url": "https://github.com/u/dsander" + } +} \ No newline at end of file diff --git a/spec/fixtures/projects.json b/spec/fixtures/projects.json new file mode 100644 index 0000000..deab4c5 --- /dev/null +++ b/spec/fixtures/projects.json @@ -0,0 +1 @@ +[{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"code":"mozart","name":"Mozart","description":null,"path":"mozart","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:57Z"},{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"}] \ No newline at end of file diff --git a/spec/fixtures/push_rule.json b/spec/fixtures/push_rule.json new file mode 100644 index 0000000..0f38ef9 --- /dev/null +++ b/spec/fixtures/push_rule.json @@ -0,0 +1 @@ +{"id": 1, "project_id": 1, "created_at": "2016-05-25T20:27:15.545Z", "commit_message_regex": "\\b[A-Z]{3}-[0-9]+\\b", "deny_delete_tag": false} diff --git a/spec/fixtures/raw_file.json b/spec/fixtures/raw_file.json new file mode 100644 index 0000000..46a991f --- /dev/null +++ b/spec/fixtures/raw_file.json @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'rails', '4.1.2' diff --git a/spec/fixtures/release_create.json b/spec/fixtures/release_create.json new file mode 100644 index 0000000..02164aa --- /dev/null +++ b/spec/fixtures/release_create.json @@ -0,0 +1 @@ +{"tag_name":"0.0.1","description":"Amazing release. Wow"} diff --git a/spec/fixtures/release_update.json b/spec/fixtures/release_update.json new file mode 100644 index 0000000..02164aa --- /dev/null +++ b/spec/fixtures/release_update.json @@ -0,0 +1 @@ +{"tag_name":"0.0.1","description":"Amazing release. Wow"} diff --git a/spec/fixtures/repository_file.json b/spec/fixtures/repository_file.json new file mode 100644 index 0000000..84c3918 --- /dev/null +++ b/spec/fixtures/repository_file.json @@ -0,0 +1 @@ +{"file_path":"path","branch_name":"branch","encoding":"base64","content":"Y29udGVudA==","commit_message":"commit message"} diff --git a/spec/fixtures/run_trigger.json b/spec/fixtures/run_trigger.json new file mode 100644 index 0000000..aa0ed2f --- /dev/null +++ b/spec/fixtures/run_trigger.json @@ -0,0 +1 @@ +{"id":8,"variables":{"a":"10"}} diff --git a/spec/fixtures/runner.json b/spec/fixtures/runner.json new file mode 100644 index 0000000..4a77c32 --- /dev/null +++ b/spec/fixtures/runner.json @@ -0,0 +1,26 @@ +{ + "active": true, + "architecture": null, + "description": "test-1-20150125", + "id": 6, + "is_shared": false, + "contacted_at": "2016-01-25T16:39:48.066Z", + "name": null, + "platform": null, + "projects": [ + { + "id": 1, + "name": "GitLab Community Edition", + "name_with_namespace": "GitLab.org / GitLab Community Edition", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" + } + ], + "token": "205086a8e3b9a2b818ffac9b89d102", + "revision": null, + "tag_list": [ + "ruby", + "mysql" + ], + "version": null +} diff --git a/spec/fixtures/runner_delete.json b/spec/fixtures/runner_delete.json new file mode 100644 index 0000000..5083086 --- /dev/null +++ b/spec/fixtures/runner_delete.json @@ -0,0 +1,7 @@ +{ + "active": true, + "description": "test-1-20150125-test", + "id": 6, + "is_shared": false, + "name": null +} diff --git a/spec/fixtures/runner_edit.json b/spec/fixtures/runner_edit.json new file mode 100644 index 0000000..abb340e --- /dev/null +++ b/spec/fixtures/runner_edit.json @@ -0,0 +1,26 @@ +{ + "active": true, + "architecture": null, + "description": "abcefg", + "id": 6, + "is_shared": false, + "contacted_at": "2016-01-25T16:39:48.066Z", + "name": null, + "platform": null, + "projects": [ + { + "id": 1, + "name": "GitLab Community Edition", + "name_with_namespace": "GitLab.org / GitLab Community Edition", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" + } + ], + "token": "205086a8e3b9a2b818ffac9b89d102", + "revision": null, + "tag_list": [ + "ruby", + "mysql" + ], + "version": null +} diff --git a/spec/fixtures/runners.json b/spec/fixtures/runners.json new file mode 100644 index 0000000..b8e5412 --- /dev/null +++ b/spec/fixtures/runners.json @@ -0,0 +1,16 @@ +[ + { + "active": true, + "description": "test-1-20150125", + "id": 6, + "is_shared": false, + "name": null + }, + { + "active": true, + "description": "test-2-20150125", + "id": 8, + "is_shared": false, + "name": null + } +] diff --git a/spec/fixtures/runners_all.json b/spec/fixtures/runners_all.json new file mode 100644 index 0000000..8e30e71 --- /dev/null +++ b/spec/fixtures/runners_all.json @@ -0,0 +1,30 @@ +[ + { + "active": true, + "description": "shared-runner-1", + "id": 1, + "is_shared": true, + "name": null + }, + { + "active": true, + "description": "shared-runner-2", + "id": 3, + "is_shared": true, + "name": null + }, + { + "active": true, + "description": "test-1-20150125", + "id": 6, + "is_shared": false, + "name": null + }, + { + "active": true, + "description": "test-2-20150125", + "id": 8, + "is_shared": false, + "name": null + } +] diff --git a/spec/fixtures/service.json b/spec/fixtures/service.json new file mode 100644 index 0000000..f278652 --- /dev/null +++ b/spec/fixtures/service.json @@ -0,0 +1 @@ +{"id":38,"title":"Redmine","created_at":"2015-12-18T14:17:17.592+03:00","updated_at":"2015-12-18T17:55:09.594+03:00","active":true,"push_events":true,"issues_events":true,"merge_requests_events":true,"tag_push_events":true,"note_events":true,"build_events":false,"properties":{"description":"Redmine","project_url":"https://example.com/projects/test_project/issue","issues_url":"https://example.com/issues/:id","new_issue_url":"'https://example.com/projects/test_project/issues/new"}} \ No newline at end of file diff --git a/spec/fixtures/session.json b/spec/fixtures/session.json new file mode 100644 index 0000000..e4f5ba3 --- /dev/null +++ b/spec/fixtures/session.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","private_token":"qEsq1pt6HJPaNciie3MG"} \ No newline at end of file diff --git a/spec/fixtures/shell_history.json b/spec/fixtures/shell_history.json new file mode 100644 index 0000000..8e4be8a --- /dev/null +++ b/spec/fixtures/shell_history.json @@ -0,0 +1,2 @@ +party on, dudes +be excellent to each other diff --git a/spec/fixtures/snippet.json b/spec/fixtures/snippet.json new file mode 100644 index 0000000..34e9d99 --- /dev/null +++ b/spec/fixtures/snippet.json @@ -0,0 +1 @@ +{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"} \ No newline at end of file diff --git a/spec/fixtures/snippet_content.json b/spec/fixtures/snippet_content.json new file mode 100644 index 0000000..e5854f9 --- /dev/null +++ b/spec/fixtures/snippet_content.json @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +puts "Cool snippet!" diff --git a/spec/fixtures/snippets.json b/spec/fixtures/snippets.json new file mode 100644 index 0000000..2645799 --- /dev/null +++ b/spec/fixtures/snippets.json @@ -0,0 +1 @@ +[{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"}] diff --git a/spec/fixtures/system_hook.json b/spec/fixtures/system_hook.json new file mode 100644 index 0000000..0028b7a --- /dev/null +++ b/spec/fixtures/system_hook.json @@ -0,0 +1 @@ +{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"} diff --git a/spec/fixtures/system_hooks.json b/spec/fixtures/system_hooks.json new file mode 100644 index 0000000..2b58791 --- /dev/null +++ b/spec/fixtures/system_hooks.json @@ -0,0 +1 @@ +[{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"}] diff --git a/spec/fixtures/tag.json b/spec/fixtures/tag.json new file mode 100644 index 0000000..1a95113 --- /dev/null +++ b/spec/fixtures/tag.json @@ -0,0 +1 @@ +{"name":"0.0.1","message":null,"commit":{"id":"c260c39f4d73d9087482d29b4d7a88bec834a3d1","message":"rubocop 100%","parent_ids":["b55be4dc5c052fb0058ef1ea96acd5e4e37f1bed"],"authored_date":"2016-04-29T16:11:32.000+01:00","author_name":"Bob Bloggs","author_email":"bob.bloggs@nowhere","committed_date":"2016-04-29T16:11:32.000+01:00","committer_name":"Bob Bloggs","committer_email":"bob.bloggs@nowhere"},"release":null} diff --git a/spec/fixtures/tag_create.json b/spec/fixtures/tag_create.json new file mode 100644 index 0000000..60e599b --- /dev/null +++ b/spec/fixtures/tag_create.json @@ -0,0 +1 @@ +{"name":"0.0.1","message":"this tag is annotated","commit":{"id":"3d3f9288d70f75aa55ea495a3ed5948a628fce11","message":"Added README.md\n","parent_ids":[],"authored_date":"2016-05-25T11:23:07.000+01:00","author_name":"Bob Bloggs","author_email":"bob.bloggs@nowhere","committed_date":"2016-05-25T11:23:07.000+01:00","committer_name":"Bob Bloggs","committer_email":"bob.bloggs@nowhere"},"release":{"tag_name":"0.0.1","description":"and it has release notes"}} diff --git a/spec/fixtures/tag_create_with_description.json b/spec/fixtures/tag_create_with_description.json new file mode 100644 index 0000000..76ce879 --- /dev/null +++ b/spec/fixtures/tag_create_with_description.json @@ -0,0 +1 @@ +{"name":"0.0.1","message":"this tag is annotated","commit":{"id":"7225ddbe28add8d168e3175266830ab8e6aabdcc","message":"Readme updated","parent_ids":["c3f101968138aa9b09a92c8b6399b3269d17865e"],"authored_date":"2016-03-07T13:38:07.000+00:00","author_name":"Bob Bloggs","author_email":"bob.bloggs@nowhere","committed_date":"2016-03-07T13:38:07.000+00:00","committer_name":"Bob Bloggs","committer_email":"bob.bloggs@nowhere"},"release":null} diff --git a/spec/fixtures/tag_delete.json b/spec/fixtures/tag_delete.json new file mode 100644 index 0000000..9eb1f86 --- /dev/null +++ b/spec/fixtures/tag_delete.json @@ -0,0 +1 @@ +{"tag_name":"0.0.1"} diff --git a/spec/fixtures/tags.json b/spec/fixtures/tags.json new file mode 100644 index 0000000..32fd6b1 --- /dev/null +++ b/spec/fixtures/tags.json @@ -0,0 +1 @@ +[{"name":"0.0.2","message":null,"commit":{"id":"c260c39f4d73d9087482d29b4d7a88bec834a3d1","message":"rubocop 100%","parent_ids":["b55be4dc5c052fb0058ef1ea96acd5e4e37f1bed"],"authored_date":"2016-04-29T16:11:32.000+01:00","author_name":"Bob Bloggs","author_email":"bob.bloggs@nowhere","committed_date":"2016-04-29T16:11:32.000+01:00","committer_name":"Bob Bloggs","committer_email":"bob.bloggs@nowhere"},"release":null},{"name":"0.0.1","message":null,"commit":{"id":"c260c39f4d73d9087482d29b4d7a88bec834a3d1","message":"rubocop 100%","parent_ids":["b55be4dc5c052fb0058ef1ea96acd5e4e37f1bed"],"authored_date":"2016-04-29T16:11:32.000+01:00","author_name":"Bob Bloggs","author_email":"bob.bloggs@nowhere","committed_date":"2016-04-29T16:11:32.000+01:00","committer_name":"Bob Bloggs","committer_email":"bob.bloggs@nowhere"},"release":null}] diff --git a/spec/fixtures/team_member.json b/spec/fixtures/team_member.json new file mode 100644 index 0000000..fd3ac38 --- /dev/null +++ b/spec/fixtures/team_member.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40} \ No newline at end of file diff --git a/spec/fixtures/team_members.json b/spec/fixtures/team_members.json new file mode 100644 index 0000000..a2fe19e --- /dev/null +++ b/spec/fixtures/team_members.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40},{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20}] \ No newline at end of file diff --git a/spec/fixtures/tree.json b/spec/fixtures/tree.json new file mode 100644 index 0000000..fe734e9 --- /dev/null +++ b/spec/fixtures/tree.json @@ -0,0 +1 @@ +[{"id":"a2cc3b0ffc1c7d06fab5642eb99ea387b57f22f8","name":"app","type":"tree","mode":"040000"},{"id":"63164bdfbc11b69f1032fbe35da0f1e9c18af2fd","name":"bin","type":"tree","mode":"040000"},{"id":"2cf682191722f20f00a371d7da58f6a35701c11d","name":"config","type":"tree","mode":"040000"},{"id":"2e76c8c1bbc46bcc762788a432d802d65a534a28","name":"db","type":"tree","mode":"040000"},{"id":"767cfc8360b50c50bb5bdde288b96a84e3efa66e","name":"doc","type":"tree","mode":"040000"},{"id":"3fa0d1024f5e372bf9e43d1dac47bd1e95ab0858","name":"lib","type":"tree","mode":"040000"},{"id":"4e79d0ac6225844602a1b9273b26d8996f777bf2","name":"log","type":"tree","mode":"040000"},{"id":"7cb7f593c6914d20fa6cc4ab5a7c34337a50e97c","name":"public","type":"tree","mode":"040000"},{"id":"d97169eef778f3cd1d4d94cbe3415b3166d15c71","name":"spec","type":"tree","mode":"040000"},{"id":"97c97da29fa97e2158cfdcdcb042af9da0bc3de4","name":"vendor","type":"tree","mode":"040000"},{"id":"d316760e4746059c117007507594a1d75b47df38","name":".gitignore","type":"blob","mode":"100644"},{"id":"f2e7cd477536f18d8e939faf452930b59a27063d","name":".travis.yml","type":"blob","mode":"100644"},{"id":"d5c68bda5f0fe703a80906f66cfe537ca807a5a6","name":"Capfile","type":"blob","mode":"100644"},{"id":"8f46eac03c6cd7ce03cda7ec3d78afdc6971e4c0","name":"Gemfile","type":"blob","mode":"100644"},{"id":"5e260573173b51eaa073661d7914fb0e935ee27f","name":"Gemfile.lock","type":"blob","mode":"100644"},{"id":"e57032f682b69f14243c09d66a0892a03b4c6045","name":"Procfile","type":"blob","mode":"100644"},{"id":"905e96da839dad683dfcf4e202bf1e030390b964","name":"README.md","type":"blob","mode":"100644"},{"id":"24a16769fd94926350a59f7b1cbd78e9e2674c57","name":"Rakefile","type":"blob","mode":"100644"},{"id":"b384d6d57c6a775a9b6bc35d79ad7f03e673a233","name":"config.ru","type":"blob","mode":"100644"}] diff --git a/spec/fixtures/trigger.json b/spec/fixtures/trigger.json new file mode 100644 index 0000000..d0657df --- /dev/null +++ b/spec/fixtures/trigger.json @@ -0,0 +1,10 @@ +{ + "id": 10, + "description": "my trigger", + "created_at": "2016-01-07T09:53:58.235Z", + "deleted_at": null, + "last_used": null, + "token": "6d056f63e50fe6f8c5f8f4aa10edb7", + "updated_at": "2016-01-07T09:53:58.235Z", + "owner": null +} diff --git a/spec/fixtures/triggers.json b/spec/fixtures/triggers.json new file mode 100644 index 0000000..35218b5 --- /dev/null +++ b/spec/fixtures/triggers.json @@ -0,0 +1,12 @@ +[ + { + "id": 10, + "description": "my trigger", + "created_at": "2016-01-07T09:53:58.235Z", + "deleted_at": null, + "last_used": null, + "token": "6d056f63e50fe6f8c5f8f4aa10edb7", + "updated_at": "2016-01-07T09:53:58.235Z", + "owner": null + } +] diff --git a/spec/fixtures/user.json b/spec/fixtures/user.json new file mode 100644 index 0000000..a7c7afb --- /dev/null +++ b/spec/fixtures/user.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","username":"john.smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"} \ No newline at end of file diff --git a/spec/fixtures/user_block_unblock.json b/spec/fixtures/user_block_unblock.json new file mode 100644 index 0000000..f32a580 --- /dev/null +++ b/spec/fixtures/user_block_unblock.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/spec/fixtures/user_email.json b/spec/fixtures/user_email.json new file mode 100644 index 0000000..dee81fe --- /dev/null +++ b/spec/fixtures/user_email.json @@ -0,0 +1 @@ +{"id":1,"email":"email@example.com"} \ No newline at end of file diff --git a/spec/fixtures/user_emails.json b/spec/fixtures/user_emails.json new file mode 100644 index 0000000..f016dc4 --- /dev/null +++ b/spec/fixtures/user_emails.json @@ -0,0 +1 @@ +[{"id":1,"email":"email@example.com"},{"id":3,"email":"email2@example.com"}] \ No newline at end of file diff --git a/spec/fixtures/user_search.json b/spec/fixtures/user_search.json new file mode 100644 index 0000000..020c82f --- /dev/null +++ b/spec/fixtures/user_search.json @@ -0,0 +1 @@ +[{"id":1,"email":"john1@example.com","name":"John Smith 1","username":"john.smith1","bio":null,"skype":"","linkedin":"","twitter":"john1","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"email":"john2@example.com","name":"John Smith 2","username":"john.smith2","bio":null,"skype":"","linkedin":"","twitter":"john2","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:56Z"}] \ No newline at end of file diff --git a/spec/fixtures/users.json b/spec/fixtures/users.json new file mode 100644 index 0000000..2695d4b --- /dev/null +++ b/spec/fixtures/users.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","username":"john.smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"email":"jack@example.com","name":"Jack Smith","username":"jack.smith","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","username":"beatrice.jewess","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","username":"felipe.davis","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","username":"michale.von","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","username":"ambrose.hansen","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","username":"alana.hahn","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"}] \ No newline at end of file diff --git a/spec/fixtures/variable.json b/spec/fixtures/variable.json new file mode 100644 index 0000000..4550c49 --- /dev/null +++ b/spec/fixtures/variable.json @@ -0,0 +1,4 @@ +{ + "key": "VARIABLE", + "value": "the value" +} diff --git a/spec/fixtures/variables.json b/spec/fixtures/variables.json new file mode 100644 index 0000000..94eea18 --- /dev/null +++ b/spec/fixtures/variables.json @@ -0,0 +1,10 @@ +[ + { + "key": "TEST_VARIABLE_1", + "value": "TEST_1" + }, + { + "key": "TEST_VARIABLE_2", + "value": "TEST_2" + } +] diff --git a/spec/gitlab/cli_helpers_spec.rb b/spec/gitlab/cli_helpers_spec.rb new file mode 100644 index 0000000..7224148 --- /dev/null +++ b/spec/gitlab/cli_helpers_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe Gitlab::CLI::Helpers do + describe ".method_owners" do + before do + @methods = Gitlab::CLI::Helpers.method_owners + end + it "should return Array of Hashes containing method names and owners" do + expect(@methods).to be_a Array + expect(@methods.all? { |m| m.is_a? Hash }).to be true + expect(@methods.all? { |m| m.keys.sort === [:name, :owner] }).to be true + end + end + + describe ".valid_command?" do + it "should return true when command is valid" do + expect(Gitlab::CLI::Helpers.valid_command? 'merge_requests').to be_truthy + end + it "should return false when command is NOT valid" do + expect(Gitlab::CLI::Helpers.valid_command? 'mmmmmerge_requests').to be_falsy + end + end + + describe ".symbolize_keys" do + context "when input is a Hash" do + it "should return a Hash with symbols for keys" do + hash = { 'key1' => 'val1', 'key2' => 'val2' } + symbolized_hash = Gitlab::CLI::Helpers.symbolize_keys(hash) + expect(symbolized_hash).to eq(key1: 'val1', key2: 'val2') + end + end + context "when input is NOT a Hash" do + it "should return input untouched" do + array = [1, 2, 3] + new_array = Gitlab::CLI::Helpers.symbolize_keys(array) + expect(new_array).to eq([1, 2, 3]) + end + end + end + + describe ".yaml_load" do + context "when argument is a YAML string" do + it "should return Ruby objects" do + argument = "{foo: bar, sna: fu}" + output = Gitlab::CLI::Helpers.yaml_load argument + expect(output).to eq('foo' => 'bar', 'sna' => 'fu') + end + end + + context "when input is NOT valid YAML" do + it "should raise" do + ruby_array = [1, 2, 3, 4] + expect { Gitlab::CLI::Helpers.yaml_load ruby_array }.to raise_error TypeError + end + end + end +end diff --git a/spec/gitlab/cli_spec.rb b/spec/gitlab/cli_spec.rb new file mode 100644 index 0000000..b3d6384 --- /dev/null +++ b/spec/gitlab/cli_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' +require 'json' + +describe Gitlab::CLI do + describe ".run" do + context "when command is version" do + it "should show gem version" do + output = capture_output { Gitlab::CLI.run('-v') } + expect(output).to eq("Gitlab Ruby Gem #{Gitlab::VERSION}\n") + end + end + + context "when command is info" do + it "should show environment info" do + output = capture_output { Gitlab::CLI.run('info') } + expect(output).to include("Gitlab endpoint is") + expect(output).to include("Gitlab private token is") + expect(output).to include("Ruby Version is") + expect(output).to include("Gitlab Ruby Gem") + end + end + + context "when command is help" do + it "should show available actions" do + output = capture_output { Gitlab::CLI.run('help') } + expect(output).to include('Help Topics') + expect(output).to include('MergeRequests') + end + end + + context "when command is user" do + before do + stub_get("/user", "user") + @output = capture_output { Gitlab::CLI.run('user') } + end + + it "should show executed command" do + expect(@output).to include('Gitlab.user') + end + + it "should show user data" do + expect(@output).to include('name') + expect(@output).to include('John Smith') + end + end + + context "when command is users" do + before do + stub_get("/users", "users") + @output = capture_output { Gitlab::CLI.run('users') } + end + + it "should show executed command" do + expect(@output).to include('Gitlab.users') + end + + it "should show users data" do + expect(@output).to include('name') + expect(@output).to include('John Smith') + expect(@output).to include('Jack Smith') + end + end + end + + describe ".start" do + context "when command with excluded fields" do + before do + stub_get("/user", "user") + args = ['user', '--except=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with excluded fields" do + expect(@output).to_not include('John Smith') + expect(@output).to include('bio') + expect(@output).to include('created_at') + end + end + + context "when command with json output" do + before do + stub_get("/user", "user") + args = ['user', '--json'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should render output as json" do + expect(JSON.parse(@output)['result']).to eq(JSON.parse(File.read(File.dirname(__FILE__) + '/../fixtures/user.json'))) + expect(JSON.parse(@output)['cmd']).to eq('Gitlab.user') + end + end + + context "when command with required fields" do + before do + stub_get("/user", "user") + args = ['user', '--only=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with required fields" do + expect(@output).to include('id') + expect(@output).to include('name') + expect(@output).to include('email') + expect(@output).to include('John Smith') + expect(@output).to_not include('bio') + expect(@output).to_not include('created_at') + end + end + + context "fetch project with namespace/repo" do + it "should encode delimiter" do + stub_get("/projects/gitlab-org%2Fgitlab-ce", "project") + args = ['project', 'gitlab-org/gitlab-ce'] + @output = capture_output { Gitlab::CLI.start(args) } + expect(@output).to include('id') + end + end + end +end diff --git a/spec/gitlab/client/branches_spec.rb b/spec/gitlab/client/branches_spec.rb new file mode 100644 index 0000000..751bb6a --- /dev/null +++ b/spec/gitlab/client/branches_spec.rb @@ -0,0 +1,99 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_protect_branch } + it { should respond_to :repo_unprotect_branch } + + describe ".branches" do + before do + stub_get("/projects/3/repository/branches", "branches") + @branches = Gitlab.branches(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches")).to have_been_made + end + + it "should return a paginated response of repository branches" do + expect(@branches).to be_a Gitlab::PaginatedResponse + expect(@branches.first.name).to eq("api") + end + end + + describe ".branch" do + before do + stub_get("/projects/3/repository/branches/api", "branch") + @branch = Gitlab.branch(3, "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches/api")).to have_been_made + end + + it "should return information about a repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".protect_branch" do + before do + stub_put("/projects/3/repository/branches/api/protect", "branch") + @branch = Gitlab.protect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/protect")).to have_been_made + end + + it "should return information about a protected repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".unprotect_branch" do + before do + stub_put("/projects/3/repository/branches/api/unprotect", "branch") + @branch = Gitlab.unprotect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/unprotect")).to have_been_made + end + + it "should return information about an unprotected repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".create_branch" do + before do + stub_post("/projects/3/repository/branches", "branch") + @branch = Gitlab.create_branch(3, "api", "master") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/branches")).to have_been_made + end + + it "should return information about a new repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".delete_branch" do + before do + stub_delete("/projects/3/repository/branches/api", "branch_delete") + @branch = Gitlab.delete_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/repository/branches/api")).to have_been_made + end + + it "should return information about the deleted repository branch" do + expect(@branch.branch_name).to eq("api") + end + end +end diff --git a/spec/gitlab/client/build_variables_spec.rb b/spec/gitlab/client/build_variables_spec.rb new file mode 100644 index 0000000..83cf117 --- /dev/null +++ b/spec/gitlab/client/build_variables_spec.rb @@ -0,0 +1,86 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".variables" do + before do + stub_get("/projects/3/variables", "variables") + @variables = Gitlab.variables(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/variables")).to have_been_made + end + + it "should return an array of project's variables" do + expect(@variables).to be_a Gitlab::PaginatedResponse + expect(@variables.first.key).to eq("TEST_VARIABLE_1") + expect(@variables.first.value).to eq("TEST_1") + end + end + + describe ".variable" do + before do + stub_get("/projects/3/variables/VARIABLE", "variable") + @variable = Gitlab.variable(3, "VARIABLE") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/variables/VARIABLE")).to have_been_made + end + + it "should return information about a variable" do + expect(@variable.key).to eq("VARIABLE") + expect(@variable.value).to eq("the value") + end + end + + describe ".create_variable" do + before do + stub_post("/projects/3/variables", "variable") + @variable = Gitlab.create_variable(3, "NEW_VARIABLE", "new value") + end + + it "should get the correct resource" do + body = { key: "NEW_VARIABLE", value: "new value" } + expect(a_post("/projects/3/variables").with(body: body)).to have_been_made + end + + it "should return information about a new variable" do + expect(@variable.key).to eq("VARIABLE") + expect(@variable.value).to eq("the value") + end + end + + describe ".update_variable" do + before do + stub_put("/projects/3/variables/UPD_VARIABLE", "variable") + @variable = Gitlab.update_variable(3, "UPD_VARIABLE", "updated value") + end + + it "should put the correct resource" do + body = { value: "updated value" } + expect(a_put("/projects/3/variables/UPD_VARIABLE").with(body: body)).to have_been_made + end + + it "should return information about an updated variable" do + expect(@variable.key).to eq("VARIABLE") + expect(@variable.value).to eq("the value") + end + end + + describe ".remove_variable" do + before do + stub_delete("/projects/3/variables/DEL_VARIABLE", "variable") + @variable = Gitlab.remove_variable(3, "DEL_VARIABLE") + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/variables/DEL_VARIABLE")).to have_been_made + end + + it "should return information about a deleted variable" do + expect(@variable.key).to eq("VARIABLE") + expect(@variable.value).to eq("the value") + end + end +end diff --git a/spec/gitlab/client/builds_spec.rb b/spec/gitlab/client/builds_spec.rb new file mode 100644 index 0000000..1c8d229 --- /dev/null +++ b/spec/gitlab/client/builds_spec.rb @@ -0,0 +1,148 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".builds" do + before do + stub_get("/projects/3/builds", "builds") + @builds = Gitlab.builds(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/builds")).to have_been_made + end + + it "should return a paginated response of project's builds" do + expect(@builds).to be_a Gitlab::PaginatedResponse + end + end + + describe ".build" do + before do + stub_get("/projects/3/builds/8", "build") + @build = Gitlab.build(3, 8) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/builds/8")).to have_been_made + end + + it "should return a single build" do + expect(@build).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a build" do + expect(@build.id).to eq(8) + expect(@build.user.name).to eq("John Smith") + end + end + + describe ".build_artifacts" do + context "when successful request" do + before do + fixture = load_fixture('build_artifacts') + fixture.set_encoding(Encoding::ASCII_8BIT) + stub_request(:get, "#{Gitlab.endpoint}/projects/3/builds/8/artifacts"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: fixture.read, headers: { 'Content-Disposition' => "attachment; filename=artifacts.zip" }) + @build_artifacts = Gitlab.build_artifacts(3, 8) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/builds/8/artifacts")).to have_been_made + end + + it "should return a FileResponse" do + expect(@build_artifacts).to be_a Gitlab::FileResponse + end + + it "should return a file with filename" do + expect(@build_artifacts.filename).to eq "artifacts.zip" + end + end + + context "when bad request" do + it "should throw an exception" do + stub_get("/projects/3/builds/8/artifacts", "error_project_not_found", 404) + expect{ Gitlab.build_artifacts(3, 8) }.to raise_error(Gitlab::Error::NotFound, "Server responded with code 404, message: 404 Project Not Found. Request URI: #{Gitlab.endpoint}/projects/3/builds/8/artifacts") + end + end + end + + describe ".builds_commits" do + before do + stub_get("/projects/3/repository/commits/0ff3ae198f8601a285adcf5c0fff204ee6fba5fd/builds", "builds_commits") + @builds_commits = Gitlab.commit_builds(3, "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/0ff3ae198f8601a285adcf5c0fff204ee6fba5fd/builds")).to have_been_made + end + + it "should return a paginated response of commit builds" do + expect(@builds_commits).to be_a Gitlab::PaginatedResponse + end + + it "should return information about the builds" do + expect(@builds_commits.count).to eq(2) + end + end + + + + describe ".build_cancel" do + before do + stub_post("/projects/3/builds/8/cancel", "build_cancel") + @build_cancel = Gitlab.build_cancel(3, 8) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/builds/8/cancel")).to have_been_made + end + + it "should return a single build" do + expect(@build_cancel).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a build" do + expect(@build_cancel.commit.author_name).to eq("John Smith") + end + end + + describe ".build_retry" do + before do + stub_post("/projects/3/builds/69/retry", "build_retry") + @build_retry = Gitlab.build_retry(3, 69) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/builds/69/retry")).to have_been_made + end + + it "should return a single build" do + expect(@build_retry).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a build" do + expect(@build_retry.commit.author_name).to eq("John Smith") + end + end + + describe ".build_erase" do + before do + stub_post("/projects/3/builds/69/erase", "build_erase") + @build_retry = Gitlab.build_erase(3, 69) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/builds/69/erase")).to have_been_made + end + + it "should return a single build" do + expect(@build_retry).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a build" do + expect(@build_retry.commit.author_name).to eq("John Smith") + end + end +end diff --git a/spec/gitlab/client/client_spec.rb b/spec/gitlab/client/client_spec.rb new file mode 100644 index 0000000..ea0e8ac --- /dev/null +++ b/spec/gitlab/client/client_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe '#inspect' do + it 'masks tokens on inspect' do + client = described_class.new(private_token: 'ui3gIYf4MMzTx-Oh5cEBx') + inspected = client.inspect + expect(inspected).to include('****************cEBx') + end + end +end diff --git a/spec/gitlab/client/commits_spec.rb b/spec/gitlab/client/commits_spec.rb new file mode 100644 index 0000000..a474efc --- /dev/null +++ b/spec/gitlab/client/commits_spec.rb @@ -0,0 +1,168 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_commits } + it { should respond_to :repo_commit } + it { should respond_to :repo_commit_diff } + it { should respond_to :repo_commit_comments } + it { should respond_to :repo_create_commit_comment } + it { should respond_to :repo_commit_status } + it { should respond_to :repo_update_commit_status } + + describe ".commits" do + before do + stub_get("/projects/3/repository/commits", "project_commits"). + with(query: { ref_name: "api" }) + @commits = Gitlab.commits(3, ref_name: "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits"). + with(query: { ref_name: "api" })).to have_been_made + end + + it "should return a paginated response of repository commits" do + expect(@commits).to be_a Gitlab::PaginatedResponse + expect(@commits.first.id).to eq("f7dd067490fe57505f7226c3b54d3127d2f7fd46") + end + end + + describe ".commit" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6", "project_commit") + @commit = Gitlab.commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6")). + to have_been_made + end + + it "should return a repository commit" do + expect(@commit.id).to eq("6104942438c14ec7bd21c6cd5bd995272b3faff6") + end + end + + describe ".commit_diff" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff", "project_commit_diff") + @diff = Gitlab.commit_diff(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff")). + to have_been_made + end + + it "should return a diff of a commit" do + expect(@diff.new_path).to eq("doc/update/5.4-to-6.0.md") + end + end + + describe ".commit_comments" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/comments", "project_commit_comments") + @commit_comments = Gitlab.commit_comments(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/comments")). + to have_been_made + end + + it "should return commit's comments" do + expect(@commit_comments).to be_a Gitlab::PaginatedResponse + expect(@commit_comments.length).to eq(2) + expect(@commit_comments[0].note).to eq("this is the 1st comment on commit 6104942438c14ec7bd21c6cd5bd995272b3faff6") + expect(@commit_comments[0].author.id).to eq(11) + expect(@commit_comments[1].note).to eq("another discussion point on commit 6104942438c14ec7bd21c6cd5bd995272b3faff6") + expect(@commit_comments[1].author.id).to eq(12) + end + end + + describe ".create_commit_comment" do + before do + stub_post("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/comments", "project_commit_comment") + @merge_request = Gitlab.create_commit_comment(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'Nice code!') + end + + it "should return information about the newly created comment" do + expect(@merge_request.note).to eq('Nice code!') + expect(@merge_request.author.id).to eq(1) + end + end + + describe ".commit_status" do + before do + stub_get("/projects/6/repository/commits/7d938cb8ac15788d71f4b67c035515a160ea76d8/statuses", 'project_commit_status'). + with(query: { all: 'true' }) + @statuses = Gitlab.commit_status(6, '7d938cb8ac15788d71f4b67c035515a160ea76d8', all: true) + end + + it "should get the correct resource" do + expect(a_get("/projects/6/repository/commits/7d938cb8ac15788d71f4b67c035515a160ea76d8/statuses"). + with(query: { all: true })) + end + + it "should get statuses of a commit" do + expect(@statuses).to be_kind_of Gitlab::PaginatedResponse + expect(@statuses.first.sha).to eq('7d938cb8ac15788d71f4b67c035515a160ea76d8') + expect(@statuses.first.ref).to eq('decreased-spec') + expect(@statuses.first.status).to eq('failed') + expect(@statuses.last.sha).to eq('7d938cb8ac15788d71f4b67c035515a160ea76d8') + expect(@statuses.last.status).to eq('success') + end + end + + describe ".update_commit_status" do + before do + stub_post("/projects/6/statuses/7d938cb8ac15788d71f4b67c035515a160ea76d8", 'project_update_commit_status'). + with(query: { name: 'test', ref: 'decreased-spec', state: 'failed' }) + @status = Gitlab.update_commit_status(6, '7d938cb8ac15788d71f4b67c035515a160ea76d8', 'failed', name: 'test', ref: 'decreased-spec') + end + + it "should get the correct resource" do + expect(a_post('/projects/6/statuses/7d938cb8ac15788d71f4b67c035515a160ea76d8'). + with(query: { name: 'test', ref: 'decreased-spec', state: 'failed' })) + end + + it "should information about the newly created status" do + expect(@status).to be_kind_of Gitlab::ObjectifiedHash + expect(@status.id).to eq(498) + expect(@status.sha).to eq('7d938cb8ac15788d71f4b67c035515a160ea76d8') + expect(@status.status).to eq('failed') + expect(@status.ref).to eq('decreased-spec') + end + end + + describe ".create_commit" do + let(:actions) do + [ + { + action: "create", + file_path: "foo/bar", + content: "some content" + } + ] + end + + let(:query) do + { + branch_name: 'dev', + commit_message: 'refactors everything', + actions: actions, + author_email: 'joe@sample.org', + author_name: 'Joe Sample' + } + end + + before do + stub_post("/projects/6/repository/commits", 'project_commit_create').with(query: query) + @commit = Gitlab.create_commit(6, 'dev', 'refactors everything', actions, {author_email: 'joe@sample.org', author_name: 'Joe Sample'}) + end + + it "should return id of a created commit" do + expect(@commit.id).to eq('ed899a2f4b50b4370feeea94676502b42383c746') + end + end +end diff --git a/spec/gitlab/client/groups_spec.rb b/spec/gitlab/client/groups_spec.rb new file mode 100644 index 0000000..c1d069e --- /dev/null +++ b/spec/gitlab/client/groups_spec.rb @@ -0,0 +1,197 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".groups" do + before do + stub_get("/groups", "groups") + stub_get("/groups/3", "group") + @group = Gitlab.group(3) + @groups = Gitlab.groups + end + + it "should get the correct resource" do + expect(a_get("/groups")).to have_been_made + expect(a_get("/groups/3")).to have_been_made + end + + it "should return a paginated response of groups" do + expect(@groups).to be_a Gitlab::PaginatedResponse + expect(@groups.first.path).to eq("threegroup") + end + end + + describe ".create_group" do + context "without description" do + before do + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + end + + it "should get the correct resource" do + expect(a_post("/groups"). + with(body: { path: 'gitlab-path', name: 'GitLab-Group' })).to have_been_made + end + + it "should return information about a created group" do + expect(@group.name).to eq("Gitlab-Group") + expect(@group.path).to eq("gitlab-group") + end + end + + context "with description" do + before do + stub_post("/groups", "group_create_with_description") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path', description: 'gitlab group description') + end + + it "should get the correct resource" do + expect(a_post("/groups"). + with(body: { path: 'gitlab-path', name: 'GitLab-Group', + description: 'gitlab group description' })).to have_been_made + end + + it "should return information about a created group" do + expect(@group.name).to eq("Gitlab-Group") + expect(@group.path).to eq("gitlab-group") + expect(@group.description).to eq("gitlab group description") + end + end + end + + describe ".delete_group" do + context "without description" do + before do + stub_delete("/groups/42", "group_delete") + @group = Gitlab.delete_group(42) + end + + it "should get the correct resource" do + expect(a_delete("/groups/42")).to have_been_made + end + + it "should return information about a deleted group" do + expect(@group.name).to eq("Gitlab-Group") + expect(@group.path).to eq("gitlab-group") + end + end + end + + describe ".transfer_project_to_group" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + + stub_post("/groups/#{@group.id}/projects/#{@project.id}", "group_create") + @group_transfer = Gitlab.transfer_project_to_group(@group.id, @project.id) + end + + it "should post to the correct resource" do + expect(a_post("/groups/#{@group.id}/projects/#{@project.id}").with(body: { id: @group.id.to_s, project_id: @project.id.to_s })).to have_been_made + end + + it "should return information about the group" do + expect(@group_transfer.name).to eq(@group.name) + expect(@group_transfer.path).to eq(@group.path) + expect(@group_transfer.id).to eq(@group.id) + end + end + + describe ".group_members" do + before do + stub_get("/groups/3/members", "group_members") + @members = Gitlab.group_members(3) + end + + it "should get the correct resource" do + expect(a_get("/groups/3/members")).to have_been_made + end + + it "should return information about a group members" do + expect(@members).to be_a Gitlab::PaginatedResponse + expect(@members.size).to eq(2) + expect(@members[1].name).to eq("John Smith") + end + end + + describe ".add_group_member" do + before do + stub_post("/groups/3/members", "group_member") + @member = Gitlab.add_group_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/groups/3/members"). + with(body: { user_id: '1', access_level: '40' })).to have_been_made + end + + it "should return information about the added member" do + expect(@member.name).to eq("John Smith") + end + end + + describe ".edit_group_member" do + before do + stub_put("/groups/3/members/1", "group_member_edit") + @member = Gitlab.edit_group_member(3, 1, 50) + end + + it "should get the correct resource" do + expect(a_put("/groups/3/members/1") + .with(body: { access_level: '50'})).to have_been_made + end + + it "should return information about the edited member" do + expect(@member.access_level).to eq(50) + end + end + + describe ".remove_group_member" do + before do + stub_delete("/groups/3/members/1", "group_member_delete") + @group = Gitlab.remove_group_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/groups/3/members/1")).to have_been_made + end + + it "should return information about the group the member was removed from" do + expect(@group.group_id).to eq(3) + end + end + + describe ".group_projects" do + before do + stub_get("/groups/4/projects", "group_projects") + @projects = Gitlab.group_projects(4) + end + + it "should get the list of projects" do + expect(a_get("/groups/4/projects")).to have_been_made + end + + it "should return a list of of projects under a group" do + expect(@projects).to be_a Gitlab::PaginatedResponse + expect(@projects.size).to eq(1) + expect(@projects[0].name).to eq("Diaspora Client") + end + end + + describe ".group_search" do + before do + stub_get("/groups?search=Group", "group_search") + @groups = Gitlab.group_search('Group') + end + + it "should get the correct resource" do + expect(a_get("/groups?search=Group")).to have_been_made + end + + it "should return an array of groups found" do + expect(@groups.first.id).to eq(5) + expect(@groups.last.id).to eq(8) + end + end +end diff --git a/spec/gitlab/client/issues_spec.rb b/spec/gitlab/client/issues_spec.rb new file mode 100644 index 0000000..543cb2a --- /dev/null +++ b/spec/gitlab/client/issues_spec.rb @@ -0,0 +1,186 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".issues" do + context "with project ID passed" do + before do + stub_get("/projects/3/issues", "project_issues") + @issues = Gitlab.issues(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues")).to have_been_made + end + + it "should return a paginated response of project's issues" do + expect(@issues).to be_a Gitlab::PaginatedResponse + expect(@issues.first.project_id).to eq(3) + end + end + + context 'with literal project ID passed' do + before do + stub_get("/projects/gitlab-org%2Fgitlab-ce/issues", "project_issues") + @issues = Gitlab.issues('gitlab-org/gitlab-ce') + end + + it "should get the correct resource" do + expect(a_get("/projects/gitlab-org%2Fgitlab-ce/issues")).to have_been_made + end + + it "should return a paginated response of project's issues" do + expect(@issues).to be_a Gitlab::PaginatedResponse + expect(@issues.first.project_id).to eq(3) + end + end + + context "without project ID passed" do + before do + stub_get("/issues", "issues") + @issues = Gitlab.issues + end + + it "should get the correct resource" do + expect(a_get("/issues")).to have_been_made + end + + it "should return a paginated response of user's issues" do + expect(@issues).to be_a Gitlab::PaginatedResponse + expect(@issues.first.closed).to be_falsey + expect(@issues.first.author.name).to eq("John Smith") + end + end + end + + describe ".issue" do + before do + stub_get("/projects/3/issues/33", "issue") + @issue = Gitlab.issue(3, 33) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/33")).to have_been_made + end + + it "should return information about an issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_issue" do + before do + stub_post("/projects/3/issues", "issue") + @issue = Gitlab.create_issue(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues"). + with(body: { title: 'title' })).to have_been_made + end + + it "should return information about a created issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".edit_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.edit_issue(3, 33, title: 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(body: { title: 'title' })).to have_been_made + end + + it "should return information about an edited issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".close_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.close_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(body: { state_event: 'close' })).to have_been_made + end + + it "should return information about an closed issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".reopen_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.reopen_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(body: { state_event: 'reopen' })).to have_been_made + end + + it "should return information about an reopened issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".subscribe_to_issue" do + before do + stub_post("/projects/3/issues/33/subscribe", "issue") + @issue = Gitlab.subscribe_to_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues/33/subscribe")).to have_been_made + end + + it "should return information about the subscribed issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".unsubscribe_from_issue" do + before do + stub_post("/projects/3/issues/33/unsubscribe", "issue") + @issue = Gitlab.unsubscribe_from_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues/33/unsubscribe")).to have_been_made + end + + it "should return information about the unsubscribed issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".delete_issue" do + before do + stub_delete("/projects/3/issues/33", "issue") + @issue = Gitlab.delete_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/issues/33")).to have_been_made + end + + it "should return information about a deleted issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.id).to eq(33) + end + end +end diff --git a/spec/gitlab/client/jobs_spec.rb b/spec/gitlab/client/jobs_spec.rb new file mode 100644 index 0000000..fcfff79 --- /dev/null +++ b/spec/gitlab/client/jobs_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe '.jobs' do + before do + stub_get('/projects/1/jobs', 'jobs') + @projects = Gitlab.jobs(1) + end + + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs')).to have_been_made + end + end + + describe '.jobs - with scopes' do + before do + stub_get('/projects/1/jobs?scope[]=created&scope[]=running', 'jobs') + @projects = Gitlab.jobs(1, scope: %w[created running]) + end + + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs?scope[]=created&scope[]=running')).to have_been_made + end + end + + describe '.pipeline_jobs' do + before do + stub_get('/projects/1/pipelines/1/jobs', 'pipeline_jobs') + @projects = Gitlab.pipeline_jobs(1, 1) + end + it 'should get the correct resource' do + expect(a_get('/projects/1/pipelines/1/jobs')).to have_been_made + end + end + + describe '.pipeline_jobs - with scope' do + before do + stub_get('/projects/1/pipelines/1/jobs?scope[]=running&scope[]=created', 'pipeline_jobs') + @projects = Gitlab.pipeline_jobs(1, 1, scope: %w[running created]) + end + it 'should get the correct resource' do + expect(a_get('/projects/1/pipelines/1/jobs?scope[]=running&scope[]=created')).to have_been_made + end + end + + describe '.job' do + before do + stub_get('/projects/1/jobs/1', 'job') + @projects = Gitlab.job(1, 1) + end + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs/1')).to have_been_made + end + end + + describe '.job_artifacts' do + before do + stub_get('/projects/1/jobs/1/artifacts', 'job') + @projects = Gitlab.job_artifacts(1, 1) + end + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs/1/artifacts')).to have_been_made + end + end + + describe '.job_artifacts_download' do + before do + stub_get('/projects/1/jobs/artifacts/master/download?job=Release%20Build', 'job') + @projects = Gitlab.job_artifacts_download(1, 'master', 'Release Build') + end + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs/artifacts/master/download?job=Release%20Build')).to have_been_made + end + end + + describe '.job_trace' do + before do + stub_get('/projects/1/jobs/1/trace', 'job_trace') + @projects = Gitlab.job_trace(1, 1) + end + it 'should get the correct resource' do + expect(a_get('/projects/1/jobs/1/trace')).to have_been_made + end + end + + describe '.job_cancel' do + before do + stub_post('/projects/1/jobs/1/cancel', 'job') + @projects = Gitlab.job_cancel(1, 1) + end + it 'should get the correct resource' do + expect(a_post('/projects/1/jobs/1/cancel')).to have_been_made + end + end + + describe '.job_retry' do + before do + stub_post('/projects/1/jobs/1/retry', 'job') + @projects = Gitlab.job_retry(1, 1) + end + it 'should get the correct resource' do + expect(a_post('/projects/1/jobs/1/retry')).to have_been_made + end + end + + describe '.job_erase' do + before do + stub_post('/projects/1/jobs/1/erase', 'job') + @projects = Gitlab.job_erase(1, 1) + end + it 'should get the correct resource' do + expect(a_post('/projects/1/jobs/1/erase')).to have_been_made + end + end + + describe '.job_play' do + before do + stub_post('/projects/1/jobs/1/play', 'job') + @projects = Gitlab.job_play(1, 1) + end + it 'should get the correct resource' do + expect(a_post('/projects/1/jobs/1/play')).to have_been_made + end + end + + describe '.job_artifacts_keep' do + before do + stub_post('/projects/1/jobs/1/artifacts/keep', 'job') + @projects = Gitlab.job_artifacts_keep(1, 1) + end + it 'should get the correct resource' do + expect(a_post('/projects/1/jobs/1/artifacts/keep')).to have_been_made + end + end +end diff --git a/spec/gitlab/client/keys_spec.rb b/spec/gitlab/client/keys_spec.rb new file mode 100644 index 0000000..f46c1f3 --- /dev/null +++ b/spec/gitlab/client/keys_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".key" do + before do + stub_get("/keys/1", "key") + @key = Gitlab.key(1) + end + + it "should get the correct resource" do + expect(a_get("/keys/1")).to have_been_made + end + + it "should return information about a key" do + expect(@key.id).to eq(1) + expect(@key.title).to eq("narkoz@helium") + end + end +end diff --git a/spec/gitlab/client/labels_spec.rb b/spec/gitlab/client/labels_spec.rb new file mode 100644 index 0000000..9c14bf2 --- /dev/null +++ b/spec/gitlab/client/labels_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".labels" do + before do + stub_get("/projects/3/labels", "labels") + @labels = Gitlab.labels(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/labels")).to have_been_made + end + + it "should return a paginated response of project's labels" do + expect(@labels).to be_a Gitlab::PaginatedResponse + expect(@labels.first.name).to eq("Backlog") + end + end + + describe ".delete" do + before do + stub_delete("/projects/3/labels", "label") + @label = Gitlab.delete_label(3, "Backlog") + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/labels"). + with(body: { name: 'Backlog' })).to have_been_made + end + + it "should return information about a deleted snippet" do + expect(@label.name).to eq("Backlog") + end + end + + describe ".edit_label" do + before do + stub_put("/projects/3/labels", "label") + @label = Gitlab.edit_label(3, "TODO", new_name: 'Backlog') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/labels"). + with(body: { name: 'TODO', new_name: "Backlog" })).to have_been_made + end + + it "should return information about an edited label" do + expect(@label.name).to eq("Backlog") + end + end + + describe ".create_label" do + before do + stub_post("/projects/3/labels", "label") + @label = Gitlab.create_label(3, 'Backlog', '#DD10AA') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/labels"). + with(body: { name: 'Backlog', color: '#DD10AA' })).to have_been_made + end + + it "should return information about a created label" do + expect(@label.name).to eq('Backlog') + expect(@label.color).to eq('#DD10AA') + end + end +end diff --git a/spec/gitlab/client/merge_requests_spec.rb b/spec/gitlab/client/merge_requests_spec.rb new file mode 100644 index 0000000..a06e91d --- /dev/null +++ b/spec/gitlab/client/merge_requests_spec.rb @@ -0,0 +1,224 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".merge_requests" do + before do + stub_get("/projects/3/merge_requests", "merge_requests") + @merge_requests = Gitlab.merge_requests(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests")).to have_been_made + end + + it "should return a paginated response of project's merge requests" do + expect(@merge_requests).to be_a Gitlab::PaginatedResponse + expect(@merge_requests.first.project_id).to eq(3) + end + end + + describe ".merge_request" do + before do + stub_get("/projects/3/merge_requests/1", "merge_request") + @merge_request = Gitlab.merge_request(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/1")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_merge_request" do + before do + stub_post("/projects/3/merge_requests", "merge_request") + end + + it "should return information about a merge request" do + @merge_request = Gitlab.create_merge_request(3, 'New feature', + source_branch: 'api', + target_branch: 'master' + ) + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".update_merge_request" do + before do + stub_put("/projects/3/merge_requests/2", "merge_request"). + with(body: { + assignee_id: '1', + target_branch: 'master', + title: 'A different new feature' + }) + @merge_request = Gitlab.update_merge_request(3, 2, + assignee_id: '1', + target_branch: 'master', + title: 'A different new feature' + ) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/merge_requests/2"). + with(body: { + assignee_id: '1', + target_branch: 'master', + title: 'A different new feature' + })).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".accept_merge_request" do + before do + stub_put("/projects/5/merge_requests/42/merge", "merge_request"). + with(body: { merge_commit_message: 'Nice!' }) + @merge_request = Gitlab.accept_merge_request(5, 42, merge_commit_message: 'Nice!') + end + + it "should get the correct resource" do + expect(a_put("/projects/5/merge_requests/42/merge"). + with(body: { merge_commit_message: 'Nice!' })).to have_been_made + end + + it "should return information about merged merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".merge_request_comments" do + before do + stub_get("/projects/3/merge_requests/2/notes", "merge_request_comments") + @merge_request = Gitlab.merge_request_comments(3, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/2/notes")).to have_been_made + end + + it "should return merge request's comments" do + expect(@merge_request).to be_an Gitlab::PaginatedResponse + expect(@merge_request.length).to eq(2) + expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") + expect(@merge_request[0].author.id).to eq(11) + expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") + expect(@merge_request[1].author.id).to eq(12) + end + end + + describe ".create_merge_request_comment" do + before do + stub_post("/projects/3/merge_requests/2/notes", "merge_request_comment") + @merge_request = Gitlab.create_merge_request_comment(3, 2, 'Cool Merge Request!') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/merge_requests/2/notes")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.note).to eq('Cool Merge Request!') + expect(@merge_request.author.id).to eq(1) + end + end + + describe ".merge_request_changes" do + before do + stub_get("/projects/3/merge_requests/2/changes", "merge_request_changes") + @mr_changes = Gitlab.merge_request_changes(3, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/2/changes")).to have_been_made + end + + it "should return the merge request changes" do + expect(@mr_changes.changes).to be_a Array + expect(@mr_changes.changes.first['old_path']).to eq('lib/omniauth/builder.rb') + expect(@mr_changes.id).to eq(2) + expect(@mr_changes.project_id).to eq(3) + expect(@mr_changes.source_branch).to eq('uncovered') + expect(@mr_changes.target_branch).to eq('master') + end + end + + describe ".merge_request_commits" do + before do + stub_get("/projects/3/merge_requests/2/commits", "merge_request_commits") + @mr_commits = Gitlab.merge_request_commits(3, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/2/commits")).to have_been_made + end + + it "should return the merge request commits" do + expect(@mr_commits).to be_a Gitlab::PaginatedResponse + expect(@mr_commits.size).to eq 2 + expect(@mr_commits.first.id).to eq "a2da7552f26d5b46a6a09bb8b7b066e3a102be7d" + expect(@mr_commits.first.short_id).to eq "a2da7552" + expect(@mr_commits.first.title).to eq "piyo" + expect(@mr_commits.first.author_name).to eq "example" + expect(@mr_commits.first.author_email).to eq "example@example.com" + expect(@mr_commits[1].short_id).to eq "3ce50959" + expect(@mr_commits[1].title).to eq "hoge" + end + end + + describe ".merge_request_closes_issues" do + before do + stub_get("/projects/5/merge_requests/1/closes_issues", "merge_request_closes_issues") + @issues = Gitlab.merge_request_closes_issues(5, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/5/merge_requests/1/closes_issues")).to have_been_made + end + + it "should return a paginated response of the issues the merge_request will close" do + expect(@issues).to be_a(Gitlab::PaginatedResponse) + expect(@issues.first.title).to eq("Merge request 1 issue 1") + expect(@issues.size).to eq(2) + end + end + + describe ".subscribe_to_merge_request" do + before do + stub_post("/projects/3/merge_requests/2/subscribe", "merge_request") + @merge_request = Gitlab.subscribe_to_merge_request(3, 2) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/merge_requests/2/subscribe")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + end + end + + describe ".unsubscribe_from_merge_request" do + before do + stub_post("/projects/3/merge_requests/2/unsubscribe", "merge_request") + @merge_request = Gitlab.unsubscribe_from_merge_request(3, 2) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/merge_requests/2/unsubscribe")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + end + end +end diff --git a/spec/gitlab/client/milestones_spec.rb b/spec/gitlab/client/milestones_spec.rb new file mode 100644 index 0000000..fdc78c9 --- /dev/null +++ b/spec/gitlab/client/milestones_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".milestones" do + before do + stub_get("/projects/3/milestones", "milestones") + @milestones = Gitlab.milestones(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones")).to have_been_made + end + + it "should return a paginated response of project's milestones" do + expect(@milestones).to be_a Gitlab::PaginatedResponse + expect(@milestones.first.project_id).to eq(3) + end + end + + describe ".milestone" do + before do + stub_get("/projects/3/milestones/1", "milestone") + @milestone = Gitlab.milestone(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones/1")).to have_been_made + end + + it "should return information about a milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".milestone_issues" do + before do + stub_get("/projects/3/milestones/1/issues", "milestone_issues") + @milestone_issues = Gitlab.milestone_issues(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones/1/issues")).to have_been_made + end + + it "should return a paginated response of milestone's issues" do + expect(@milestone_issues).to be_a Gitlab::PaginatedResponse + expect(@milestone_issues.first.milestone.id).to eq(1) + end + end + + describe ".milestone_merge_requests" do + before do + stub_get("/projects/3/milestones/1/merge_requests", "milestone_merge_requests") + @milestone_merge_requests = Gitlab.milestone_merge_requests(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones/1/merge_requests")).to have_been_made + end + + it "should return a paginated response of milestone's merge_requests" do + expect(@milestone_merge_requests).to be_a Gitlab::PaginatedResponse + expect(@milestone_merge_requests.first.milestone.id).to eq(1) + end + end + + describe ".create_milestone" do + before do + stub_post("/projects/3/milestones", "milestone") + @milestone = Gitlab.create_milestone(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/milestones"). + with(body: { title: 'title' })).to have_been_made + end + + it "should return information about a created milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".edit_milestone" do + before do + stub_put("/projects/3/milestones/33", "milestone") + @milestone = Gitlab.edit_milestone(3, 33, title: 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/milestones/33"). + with(body: { title: 'title' })).to have_been_made + end + + it "should return information about an edited milestone" do + expect(@milestone.project_id).to eq(3) + end + end +end diff --git a/spec/gitlab/client/namespaces_spec.rb b/spec/gitlab/client/namespaces_spec.rb new file mode 100644 index 0000000..5b94787 --- /dev/null +++ b/spec/gitlab/client/namespaces_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :namespaces } + + describe ".namespaces" do + before do + stub_get("/namespaces", "namespaces") + @namespaces = Gitlab.namespaces + end + + it "should get the correct resource" do + expect(a_get("/namespaces")).to have_been_made + end + + it "should return a paginated response of namespaces" do + expect(@namespaces).to be_a Gitlab::PaginatedResponse + expect(@namespaces.first.path).to eq("john") + expect(@namespaces.first.kind).to eq("user") + end + end +end diff --git a/spec/gitlab/client/notes_spec.rb b/spec/gitlab/client/notes_spec.rb new file mode 100644 index 0000000..b8557db --- /dev/null +++ b/spec/gitlab/client/notes_spec.rb @@ -0,0 +1,205 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe "notes" do + context "when wall notes" do + before do + stub_get("/projects/3/notes", "notes") + @notes = Gitlab.notes(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes")).to have_been_made + end + + it "should return a paginated response of notes" do + expect(@notes).to be_a Gitlab::PaginatedResponse + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when issue notes" do + before do + stub_get("/projects/3/issues/7/notes", "notes") + @notes = Gitlab.issue_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes")).to have_been_made + end + + it "should return a paginated response of notes" do + expect(@notes).to be_a Gitlab::PaginatedResponse + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when snippet notes" do + before do + stub_get("/projects/3/snippets/7/notes", "notes") + @notes = Gitlab.snippet_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes")).to have_been_made + end + + it "should return a paginated response of notes" do + expect(@notes).to be_a Gitlab::PaginatedResponse + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when merge_request notes" do + before do + stub_get("/projects/3/merge_requests/7/notes", "notes") + @notes = Gitlab.merge_request_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/7/notes")).to have_been_made + end + + it "should return a paginated response of notes" do + expect(@notes).to be_a Gitlab::PaginatedResponse + expect(@notes.first.author.name).to eq("John Smith") + end + end + end + + describe "note" do + context "when wall note" do + before do + stub_get("/projects/3/notes/1201", "note") + @note = Gitlab.note(3, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_get("/projects/3/issues/7/notes/1201", "note") + @note = Gitlab.issue_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_get("/projects/3/snippets/7/notes/1201", "note") + @note = Gitlab.snippet_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when merge request note" do + before do + stub_get("/projects/3/merge_requests/7/notes/1201", "note") + @note = Gitlab.merge_request_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end + + describe "create note" do + context "when wall note" do + before do + stub_post("/projects/3/notes", "note") + @note = Gitlab.create_note(3, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/notes"). + with(body: { body: 'The solution is rather tricky' })).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_post("/projects/3/issues/7/notes", "note") + @note = Gitlab.create_issue_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues/7/notes"). + with(body: { body: 'The solution is rather tricky' })).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_post("/projects/3/snippets/7/notes", "note") + @note = Gitlab.create_snippet_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/snippets/7/notes"). + with(body: { body: 'The solution is rather tricky' })).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when merge_request note" do + before do + stub_post("/projects/3/merge_requests/7/notes", "note") + @note = Gitlab.create_merge_request_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/merge_requests/7/notes"). + with(body: { body: 'The solution is rather tricky' })).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end +end diff --git a/spec/gitlab/client/pipeline_triggers_spec.rb b/spec/gitlab/client/pipeline_triggers_spec.rb new file mode 100644 index 0000000..ce5fd24 --- /dev/null +++ b/spec/gitlab/client/pipeline_triggers_spec.rb @@ -0,0 +1,157 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :delete_trigger } + + describe ".triggers" do + before do + stub_get("/projects/3/triggers", "triggers") + @triggers = Gitlab.triggers(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/triggers")).to have_been_made + end + + it "should return an array of project's triggers" do + expect(@triggers).to be_a Gitlab::PaginatedResponse + expect(@triggers.first.token).to eq("6d056f63e50fe6f8c5f8f4aa10edb7") + end + end + + describe ".trigger" do + before do + stub_get("/projects/3/triggers/10", "trigger") + @trigger = Gitlab.trigger(3, 10) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/triggers/10")).to have_been_made + end + + it "should return information about a trigger" do + expect(@trigger.created_at).to eq("2016-01-07T09:53:58.235Z") + expect(@trigger.token).to eq("6d056f63e50fe6f8c5f8f4aa10edb7") + end + end + + describe ".create_trigger" do + before do + stub_post("/projects/3/triggers", "trigger") + @trigger = Gitlab.create_trigger(3, "my description") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/triggers"). + with(body: { description: "my description" })).to have_been_made + end + + it "should return information about a new trigger" do + expect(@trigger.created_at).to eq("2016-01-07T09:53:58.235Z") + expect(@trigger.token).to eq("6d056f63e50fe6f8c5f8f4aa10edb7") + end + end + + describe ".update_trigger" do + before do + stub_put("/projects/3/triggers/1", "trigger") + @trigger = Gitlab.update_trigger(3, 1, description: "my description") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/triggers/1"). + with(body: { description: "my description" })).to have_been_made + end + + it "should return information about the trigger" do + expect(@trigger.created_at).to eq("2016-01-07T09:53:58.235Z") + expect(@trigger.token).to eq("6d056f63e50fe6f8c5f8f4aa10edb7") + end + end + + describe ".trigger_take_ownership" do + before do + stub_post("/projects/3/triggers/1/take_ownership", "trigger") + @trigger = Gitlab.trigger_take_ownership(3, 1) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/triggers/1/take_ownership")).to have_been_made + end + + it "should return information about the trigger" do + expect(@trigger.created_at).to eq("2016-01-07T09:53:58.235Z") + expect(@trigger.token).to eq("6d056f63e50fe6f8c5f8f4aa10edb7") + end + end + + describe ".remove_trigger" do + before do + stub_delete("/projects/3/triggers/10", "empty") + @trigger = Gitlab.remove_trigger(3, 10) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/triggers/10")).to have_been_made + end + end + + describe ".run_trigger" do + before do + stub_request(:post, "#{Gitlab.endpoint}/projects/3/trigger/pipeline"). + to_return(body: load_fixture("run_trigger"), status: 200) + end + + context "when private_token is not set" do + before do + Gitlab.private_token = nil + end + + it "should not raise Error::MissingCredentials" do + expect { Gitlab.run_trigger(3, "7b9148c158980bbd9bcea92c17522d", "master", {a: 10}) }.to_not raise_error + end + + after do + Gitlab.private_token = 'secret' + end + end + + context "without variables" do + before do + @trigger = Gitlab.run_trigger(3, "7b9148c158980bbd9bcea92c17522d", "master") + end + + it "should get the correct resource" do + expect(a_request(:post, "#{Gitlab.endpoint}/projects/3/trigger/pipeline"). + with(body: { + token: "7b9148c158980bbd9bcea92c17522d", + ref: "master" + })).to have_been_made + end + + it "should return information about the triggered build" do + expect(@trigger.id).to eq(8) + end + end + + context "with variables" do + before do + @trigger = Gitlab.run_trigger(3, "7b9148c158980bbd9bcea92c17522d", "master", {a: 10}) + end + + it "should get the correct resource" do + expect(a_request(:post, "#{Gitlab.endpoint}/projects/3/trigger/pipeline"). + with(body: { + token: "7b9148c158980bbd9bcea92c17522d", + ref: "master", + variables: {a: "10"} + })).to have_been_made + end + + it "should return information about the triggered build" do + expect(@trigger.id).to eq(8) + expect(@trigger.variables.a).to eq("10") + end + end + end +end diff --git a/spec/gitlab/client/pipelines_spec.rb b/spec/gitlab/client/pipelines_spec.rb new file mode 100644 index 0000000..3e5406a --- /dev/null +++ b/spec/gitlab/client/pipelines_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".pipelines" do + before do + stub_get("/projects/3/pipelines", "pipelines") + @pipelines = Gitlab.pipelines(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/pipelines")).to have_been_made + end + + it "should return a paginated response of project's pipelines" do + expect(@pipelines).to be_a Gitlab::PaginatedResponse + end + end + + describe ".pipeline" do + before do + stub_get("/projects/3/pipelines/46", "pipeline") + @pipeline = Gitlab.pipeline(3, 46) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/pipelines/46")).to have_been_made + end + + it "should return a single pipeline" do + expect(@pipeline).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a pipeline" do + expect(@pipeline.id).to eq(46) + expect(@pipeline.user.name).to eq("Administrator") + end + end + + describe ".create_pipeline" do + before do + stub_post("/projects/3/pipeline?ref=master", "pipeline_create") + @pipeline_create = Gitlab.create_pipeline(3, 'master') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/pipeline?ref=master")).to have_been_made + end + + it "should return a single pipeline" do + expect(@pipeline_create).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a pipeline" do + expect(@pipeline_create.user.name).to eq("Administrator") + end + end + + describe ".cancel_pipeline" do + before do + stub_post("/projects/3/pipelines/46/cancel", "pipeline_cancel") + @pipeline_cancel = Gitlab.cancel_pipeline(3, 46) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/pipelines/46/cancel")).to have_been_made + end + + it "should return a single pipeline" do + expect(@pipeline_cancel).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a pipeline" do + expect(@pipeline_cancel.user.name).to eq("Administrator") + end + end + + describe ".retry_pipeline" do + before do + stub_post("/projects/3/pipelines/46/retry", "pipeline_retry") + @pipeline_retry = Gitlab.retry_pipeline(3, 46) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/pipelines/46/retry")).to have_been_made + end + + it "should return a single pipeline" do + expect(@pipeline_retry).to be_a Gitlab::ObjectifiedHash + end + + it "should return information about a pipeline" do + expect(@pipeline_retry.user.name).to eq("Administrator") + end + end +end diff --git a/spec/gitlab/client/projects_spec.rb b/spec/gitlab/client/projects_spec.rb new file mode 100644 index 0000000..d2c6e47 --- /dev/null +++ b/spec/gitlab/client/projects_spec.rb @@ -0,0 +1,603 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :search_projects } + + describe ".projects" do + before do + stub_get("/projects", "projects") + @projects = Gitlab.projects + end + + it "should get the correct resource" do + expect(a_get("/projects")).to have_been_made + end + + it "should return a paginated response of projects" do + expect(@projects).to be_a Gitlab::PaginatedResponse + expect(@projects.first.name).to eq("Brute") + expect(@projects.first.owner.name).to eq("John Smith") + end + end + + describe ".project_search" do + before do + stub_get("/projects/search/Gitlab", "project_search") + @project_search = Gitlab.project_search("Gitlab") + end + + it "should get the correct resource" do + expect(a_get("/projects/search/Gitlab")).to have_been_made + end + + it "should return a paginated response of projects found" do + expect(@project_search).to be_a Gitlab::PaginatedResponse + expect(@project_search.first.name).to eq("Gitlab") + expect(@project_search.first.owner.name).to eq("John Smith") + end + end + + describe ".project" do + before do + stub_get("/projects/3", "project") + @project = Gitlab.project(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3")).to have_been_made + end + + it "should return information about a project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".project_events" do + before do + stub_get("/projects/2/events", "project_events") + @events = Gitlab.project_events(2) + end + + it "should get the correct resource" do + expect(a_get("/projects/2/events")).to have_been_made + end + + it "should return a paginated response of events" do + expect(@events).to be_a Gitlab::PaginatedResponse + expect(@events.size).to eq(2) + end + + it "should return the action name of the event" do + expect(@events.first.action_name).to eq("opened") + end + end + + describe ".create_project" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_post("/projects")).to have_been_made + end + + it "should return information about a created project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".create_project for user" do + before do + stub_post("/users", "user") + @owner = Gitlab.create_user("john@example.com", "pass", name: 'John Owner') + stub_post("/projects/user/#{@owner.id}", "project_for_user") + @project = Gitlab.create_project('Brute', user_id: @owner.id) + end + + it "should return information about a created project" do + expect(@project.name).to eq("Brute") + expect(@project.owner.name).to eq("John Owner") + end + end + + describe ".delete_project" do + before do + stub_delete("/projects/Gitlab", "project") + @project = Gitlab.delete_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_delete("/projects/Gitlab")).to have_been_made + end + + it "should return information about a deleted project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".create_fork" do + context "without sudo option" do + before do + stub_post("/projects/3/fork", "project_fork") + @project = Gitlab.create_fork(3) + end + + it "should post to the correct resource" do + expect(a_post("/projects/3/fork")).to have_been_made + end + + it "should return information about the forked project" do + expect(@project.forked_from_project.id).to eq(3) + expect(@project.id).to eq(20) + end + end + + context "with the sudo option" do + before do + stub_post("/projects/3/fork", "project_forked_for_user") + @sudoed_username = 'jack.smith' + @project = Gitlab.create_fork(3, sudo: @sudoed_username) + end + + it "should post to the correct resource" do + expect(a_post("/projects/3/fork")).to have_been_made + end + + it "should return information about the forked project" do + expect(@project.forked_from_project.id).to eq(3) + expect(@project.id).to eq(20) + expect(@project.owner.username).to eq(@sudoed_username) + end + end + end + + describe ".team_members" do + before do + stub_get("/projects/3/members", "team_members") + @team_members = Gitlab.team_members(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members")).to have_been_made + end + + it "should return a paginated response of team members" do + expect(@team_members).to be_a Gitlab::PaginatedResponse + expect(@team_members.first.name).to eq("John Smith") + end + end + + describe ".team_member" do + before do + stub_get("/projects/3/members/1", "team_member") + @team_member = Gitlab.team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members/1")).to have_been_made + end + + it "should return information about a team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".add_team_member" do + before do + stub_post("/projects/3/members", "team_member") + @team_member = Gitlab.add_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/members"). + with(body: { user_id: '1', access_level: '40' })).to have_been_made + end + + it "should return information about an added team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".edit_team_member" do + before do + stub_put("/projects/3/members/1", "team_member") + @team_member = Gitlab.edit_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/members/1"). + with(body: { access_level: '40' })).to have_been_made + end + + it "should return information about an edited team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".remove_team_member" do + before do + stub_delete("/projects/3/members/1", "team_member") + @team_member = Gitlab.remove_team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/members/1")).to have_been_made + end + + it "should return information about a removed team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".project_hooks" do + before do + stub_get("/projects/1/hooks", "project_hooks") + @hooks = Gitlab.project_hooks(1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks")).to have_been_made + end + + it "should return a paginated response of hooks" do + expect(@hooks).to be_a Gitlab::PaginatedResponse + expect(@hooks.first.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".project_hook" do + before do + stub_get("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".add_project_hook" do + context "without specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = { url: "https://api.example.net/v1/webhooks/ci" } + expect(a_post("/projects/1/hooks").with(body: body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + context "with specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci", push_events: true, merge_requests_events: true) + end + + it "should get the correct resource" do + body = { url: "https://api.example.net/v1/webhooks/ci", push_events: "true", merge_requests_events: "true" } + expect(a_post("/projects/1/hooks").with(body: body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + end + + describe ".edit_project_hook" do + before do + stub_put("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.edit_project_hook(1, 1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = { url: "https://api.example.net/v1/webhooks/ci" } + expect(a_put("/projects/1/hooks/1").with(body: body)).to have_been_made + end + + it "should return information about an edited hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".edit_project" do + before do + stub_put("/projects/3", "project_edit").with(query: { name: "Gitlab-edit" }) + @edited_project = Gitlab.edit_project(3, name: "Gitlab-edit") + end + + it "should get the correct resource" do + expect(a_put("/projects/3").with(query: { name: "Gitlab-edit" })).to have_been_made + end + + it "should return information about an edited project" do + expect(@edited_project.name).to eq("Gitlab-edit") + end + end + + describe ".delete_project_hook" do + context "when empty response" do + before do + stub_request(:delete, "#{Gitlab.endpoint}/projects/1/hooks/1"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: '') + @hook = Gitlab.delete_project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/hooks/1")).to have_been_made + end + + it "should return false" do + expect(@hook).to be(false) + end + end + + context "when JSON response" do + before do + stub_delete("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.delete_project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a deleted hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + end + + describe ".push_rule" do + before do + stub_get("/projects/1/push_rule", "push_rule") + @push_rule = Gitlab.push_rule(1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/push_rule")).to have_been_made + end + + it "should return information about a push rule" do + expect(@push_rule.commit_message_regex).to eq("\\b[A-Z]{3}-[0-9]+\\b") + end + end + + describe ".add_push_rule" do + before do + stub_post("/projects/1/push_rule", "push_rule") + @push_rule = Gitlab.add_push_rule(1, { deny_delete_tag: false, commit_message_regex: "\\b[A-Z]{3}-[0-9]+\\b" }) + end + + it "should get the correct resource" do + expect(a_post("/projects/1/push_rule")).to have_been_made + end + + it "should return information about an added push rule" do + expect(@push_rule.commit_message_regex).to eq("\\b[A-Z]{3}-[0-9]+\\b") + end + end + + describe ".edit_push_rule" do + before do + stub_put("/projects/1/push_rule", "push_rule") + @push_rule = Gitlab.edit_push_rule(1, { deny_delete_tag: false, commit_message_regex: "\\b[A-Z]{3}-[0-9]+\\b" }) + end + + it "should get the correct resource" do + expect(a_put("/projects/1/push_rule")).to have_been_made + end + + it "should return information about an edited push rule" do + expect(@push_rule.commit_message_regex).to eq("\\b[A-Z]{3}-[0-9]+\\b") + end + end + + describe ".delete_push_rule" do + context "when empty response" do + before do + stub_request(:delete, "#{Gitlab.endpoint}/projects/1/push_rule"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: '') + @push_rule = Gitlab.delete_push_rule(1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/push_rule")).to have_been_made + end + + it "should return false" do + expect(@push_rule).to be(false) + end + end + + context "when JSON response" do + before do + stub_delete("/projects/1/push_rule", "push_rule") + @push_rule = Gitlab.delete_push_rule(1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/push_rule")).to have_been_made + end + + it "should return information about a deleted push rule" do + expect(@push_rule.commit_message_regex).to eq("\\b[A-Z]{3}-[0-9]+\\b") + end + end + end + + describe ".make_forked_from" do + before do + stub_post("/projects/42/fork/24", "project_fork_link") + @forked_project_link = Gitlab.make_forked_from(42, 24) + end + + it "should get the correct resource" do + expect(a_post("/projects/42/fork/24")).to have_been_made + end + + it "should return information about a forked project" do + expect(@forked_project_link.forked_from_project_id).to eq(24) + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".remove_forked" do + before do + stub_delete("/projects/42/fork", "project_fork_link") + @forked_project_link = Gitlab.remove_forked(42) + end + + it "should be sent to correct resource" do + expect(a_delete("/projects/42/fork")).to have_been_made + end + + it "should return information about an unforked project" do + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".deploy_keys" do + before do + stub_get("/projects/42/deploy_keys", "project_keys") + @deploy_keys = Gitlab.deploy_keys(42) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/deploy_keys")).to have_been_made + end + + it "should return project deploy keys" do + expect(@deploy_keys).to be_a Gitlab::PaginatedResponse + expect(@deploy_keys.first.id).to eq 2 + expect(@deploy_keys.first.title).to eq "Key Title" + expect(@deploy_keys.first.key).to match(/ssh-rsa/) + end + end + + describe ".deploy_key" do + before do + stub_get("/projects/42/deploy_keys/2", "project_key") + @deploy_key = Gitlab.deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/deploy_keys/2")).to have_been_made + end + + it "should return project deploy key" do + expect(@deploy_key.id).to eq 2 + expect(@deploy_key.title).to eq "Key Title" + expect(@deploy_key.key).to match(/ssh-rsa/) + end + end + + describe ".delete_deploy_key" do + before do + stub_delete("/projects/42/deploy_keys/2", "project_key") + @deploy_key = Gitlab.delete_deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_delete("/projects/42/deploy_keys/2")).to have_been_made + end + + it "should return information about a deleted key" do + expect(@deploy_key.id).to eq(2) + end + end + + describe ".enable_deploy_key" do + before do + stub_post("/projects/42/deploy_keys/2/enable", "project_key") + @deploy_key = Gitlab.enable_deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_post("/projects/42/deploy_keys/2/enable"). + with(body: { id: '42', key_id: '2' })).to have_been_made + end + + it "should return information about an enabled key" do + expect(@deploy_key.id).to eq(2) + end + end + + describe ".disable_deploy_key" do + before do + stub_post("/projects/42/deploy_keys/2/disable", "project_key") + @deploy_key = Gitlab.disable_deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_post("/projects/42/deploy_keys/2/disable"). + with(body: { id: '42', key_id: '2' })).to have_been_made + end + + it "should return information about a disabled key" do + expect(@deploy_key.id).to eq(2) + end + end + + describe ".share_project_with_group" do + before do + stub_post("/projects/3/share", "group") + @group = Gitlab.share_project_with_group(3, 10, 40) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/share"). + with(body: { group_id: '10', group_access: '40' })).to have_been_made + end + + it "should return information about an added group" do + expect(@group.id).to eq(10) + end + end + + describe ".star_project" do + before do + stub_post("/projects/3/star", "project_star") + @starred_project = Gitlab.star_project(3) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/star")).to have_been_made + end + + it "should return information about the starred project" do + expect(@starred_project.id).to eq(3) + end + end + + describe ".unstar_project" do + before do + stub_delete("/projects/3/star", "project_unstar") + @unstarred_project = Gitlab.unstar_project(3) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/star")).to have_been_made + end + + it "should return information about the unstarred project" do + expect(@unstarred_project.id).to eq(3) + end + end +end diff --git a/spec/gitlab/client/repositories_spec.rb b/spec/gitlab/client/repositories_spec.rb new file mode 100644 index 0000000..c972d31 --- /dev/null +++ b/spec/gitlab/client/repositories_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_tags } + it { should respond_to :repo_create_tag } + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_tree } + it { should respond_to :repo_compare } + + describe ".tags" do + before do + stub_get("/projects/3/repository/tags", "project_tags") + @tags = Gitlab.tags(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tags")).to have_been_made + end + + it "should return a paginated response of repository tags" do + expect(@tags).to be_a Gitlab::PaginatedResponse + expect(@tags.first.name).to eq("v2.8.2") + end + end + + describe ".create_tag" do + context "when lightweight" do + before do + stub_post("/projects/3/repository/tags", "project_tag_lightweight") + @tag = Gitlab.create_tag(3, 'v1.0.0', '2695effb5807a22ff3d138d593fd856244e155e7') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags")).to have_been_made + end + + it "should return information about a new repository tag" do + expect(@tag.name).to eq("v1.0.0") + expect(@tag.message).to eq(nil) + end + end + + context "when annotated" do + before do + stub_post("/projects/3/repository/tags", "project_tag_annotated") + @tag = Gitlab.create_tag(3, 'v1.1.0', '2695effb5807a22ff3d138d593fd856244e155e7', 'Release 1.1.0') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags")).to have_been_made + end + + it "should return information about a new repository tag" do + expect(@tag.name).to eq("v1.1.0") + expect(@tag.message).to eq("Release 1.1.0") + end + end + end + + describe ".tree" do + before do + stub_get("/projects/3/repository/tree", "tree") + @tree = Gitlab.tree(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tree")).to have_been_made + end + + it "should return a paginated response of repository tree files (root level)" do + expect(@tree).to be_a Gitlab::PaginatedResponse + expect(@tree.first.name).to eq("app") + end + end + + describe ".compare" do + before do + stub_get("/projects/3/repository/compare", "compare_merge_request_diff"). + with(query: { from: "master", to: "feature" }) + @diff = Gitlab.compare(3, 'master', 'feature') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/compare"). + with(query: { from: "master", to: "feature" })).to have_been_made + end + + it "should get diffs of a merge request" do + expect(@diff.diffs).to be_kind_of Array + expect(@diff.diffs.last["new_path"]).to eq "files/js/application.js" + end + end +end diff --git a/spec/gitlab/client/repository_files_spec.rb b/spec/gitlab/client/repository_files_spec.rb new file mode 100644 index 0000000..6900884 --- /dev/null +++ b/spec/gitlab/client/repository_files_spec.rb @@ -0,0 +1,77 @@ +require "spec_helper" + +describe Gitlab::Client do + describe ".file_contents" do + before do + stub_get("/projects/3/repository/files/Gemfile/raw?ref=master", "raw_file") + @file_contents = Gitlab.file_contents(3, "Gemfile") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/files/Gemfile/raw?ref=master")).to have_been_made + end + + it "should return file contents" do + expect(@file_contents).to eq("source 'https://rubygems.org'\ngem 'rails', '4.1.2'\n") + end + end + + describe ".get_file" do + before do + stub_get("/projects/3/repository/files/README%2Emd?ref=master", "get_repository_file") + @file = Gitlab.get_file(3, 'README.md', 'master') + end + + it "should create the correct resource" do + expect(a_get("/projects/3/repository/files/README%2Emd?ref=master")).to have_been_made + end + + it "should return the base64 encoded file" do + expect(@file.file_path).to eq "README.md" + expect(@file.ref).to eq "master" + expect(@file.content).to eq "VGhpcyBpcyBhICpSRUFETUUqIQ==\n" + end + end + + describe ".create_file" do + let!(:request_stub) { stub_post("/projects/3/repository/files", "repository_file") } + let!(:file) { Gitlab.create_file(3, "path", "branch", "content", "commit message") } + + it "should create the correct resource" do + expect(request_stub).to have_been_made + end + + it "should return information about the new file" do + expect(file.file_path).to eq "path" + expect(file.branch_name).to eq "branch" + end + end + + describe ".edit_file" do + let!(:request_stub) { stub_put("/projects/3/repository/files", "repository_file") } + let!(:file) { Gitlab.edit_file(3, "path", "branch", "content", "commit message") } + + it "should create the correct resource" do + expect(request_stub).to have_been_made + end + + it "should return information about the new file" do + expect(file.file_path).to eq "path" + expect(file.branch_name).to eq "branch" + end + end + + describe ".remove_file" do + let!(:request_stub) { stub_delete("/projects/3/repository/files", "repository_file") } + let!(:file) { Gitlab.remove_file(3, "path", "branch", "commit message") } + + it "should create the correct resource" do + expect(request_stub).to have_been_made + end + + it "should return information about the new file" do + expect(file.file_path).to eq "path" + expect(file.branch_name).to eq "branch" + end + end +end diff --git a/spec/gitlab/client/runners_spec.rb b/spec/gitlab/client/runners_spec.rb new file mode 100644 index 0000000..0eb43b8 --- /dev/null +++ b/spec/gitlab/client/runners_spec.rb @@ -0,0 +1,185 @@ +require 'spec_helper' + +describe Gitlab::Client do + + describe ".runners" do + before do + stub_get("/runners", "runners") + end + + context 'without scope' do + before do + @runner = Gitlab.runners + end + + it "should get the correct resource" do + expect(a_get("/runners")).to have_been_made + end + + it "should return a paginated response of runners" do + expect(@runner).to be_a Gitlab::PaginatedResponse + expect(@runner.first.id).to eq(6) + expect(@runner.first.description).to eq('test-1-20150125') + end + end + + context 'with scope' do + before do + stub_get("/runners?scope=online", "runners") + @runner = Gitlab.runners({scope: :online}) + end + + it "should get the correct resource" do + expect(a_get("/runners").with(query: { scope: :online })).to have_been_made + end + + it "should return a paginated response of runners" do + expect(@runner).to be_a Gitlab::PaginatedResponse + expect(@runner.first.id).to eq(6) + expect(@runner.first.description).to eq('test-1-20150125') + end + end + + end + + describe ".all_runners" do + before do + stub_get("/runners/all", "runners") + end + + context 'without scope' do + before do + @runner = Gitlab.all_runners + end + + it "should get the correct resource" do + expect(a_get("/runners/all")).to have_been_made + end + + it "should return a paginated response of runners" do + expect(@runner).to be_a Gitlab::PaginatedResponse + expect(@runner.first.id).to eq(6) + expect(@runner.first.description).to eq('test-1-20150125') + end + end + + context 'with scope' do + before do + stub_get("/runners/all?scope=online", "runners") + @runner = Gitlab.all_runners({scope: :online}) + end + + it "should get the correct resource" do + expect(a_get("/runners/all").with(query: { scope: :online })).to have_been_made + end + + it "should return a paginated response of runners" do + expect(@runner).to be_a Gitlab::PaginatedResponse + expect(@runner.first.id).to eq(6) + expect(@runner.first.description).to eq('test-1-20150125') + end + end + end + + describe ".runner" do + before do + stub_get("/runners/6", "runner") + @runners = Gitlab.runner(6) + end + + it "should get the correct resource" do + expect(a_get("/runners/6")).to have_been_made + end + + it "should return a response of a runner" do + expect(@runners).to be_a Gitlab::ObjectifiedHash + expect(@runners.id).to eq(6) + expect(@runners.description).to eq('test-1-20150125') + end + end + + describe ".update_runner" do + before do + stub_put("/runners/6", "runner_edit").with(query: { description: "abcefg" }) + @runner = Gitlab.update_runner(6, description: "abcefg" ) + end + + it "should get the correct resource" do + expect(a_put("/runners/6").with(query: { description: "abcefg" })).to have_been_made + end + + it "should return an updated response of a runner" do + expect(@runner).to be_a Gitlab::ObjectifiedHash + expect(@runner.description).to eq('abcefg') + end + end + + describe ".delete_runner" do + before do + stub_delete("/runners/6", "runner_delete") + @runner = Gitlab.delete_runner(6) + end + + it "should get the correct resource" do + expect(a_delete("/runners/6")).to have_been_made + end + + it "should return a response of the deleted runner" do + expect(@runner).to be_a Gitlab::ObjectifiedHash + expect(@runner.id).to eq(6) + end + end + + describe ".project_runners" do + before do + stub_get("/projects/1/runners", "project_runners") + @runners = Gitlab.project_runners(1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/runners")).to have_been_made + end + + it "should return a paginated response of runners" do + expect(@runners).to be_a Gitlab::PaginatedResponse + expect(@runners.first.id).to eq(8) + expect(@runners.first.description).to eq('test-2-20150125') + end + end + + describe ".project_enable_runner" do + before do + stub_post("/projects/1/runners", "runner") + @runner = Gitlab.project_enable_runner(1, 6) + end + + it "should get the correct resource" do + expect(a_post("/projects/1/runners")).to have_been_made + end + + it "should return a response of the enabled runner" do + expect(@runner).to be_a Gitlab::ObjectifiedHash + expect(@runner.id).to eq(6) + expect(@runner.description).to eq('test-1-20150125') + end + end + + describe ".project_disable_runner" do + before do + stub_delete("/projects/1/runners/6", "runner") + @runner = Gitlab.project_disable_runner(1, 6) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/runners/6")).to have_been_made + end + + it "should return a response of the disabled runner" do + expect(@runner).to be_a Gitlab::ObjectifiedHash + expect(@runner.id).to eq(6) + expect(@runner.description).to eq('test-1-20150125') + end + end + + +end diff --git a/spec/gitlab/client/services_spec.rb b/spec/gitlab/client/services_spec.rb new file mode 100644 index 0000000..7a093bb --- /dev/null +++ b/spec/gitlab/client/services_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".service" do + before do + stub_get("/projects/3/services/redmine", "service") + @service = Gitlab.service(3, :redmine) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/services/redmine")).to have_been_made + end + + it "should return a information about a service of project" do + expect(@service.id).to eq 38 + expect(@service.title).to eq("Redmine") + expect(@service.properties.project_url).to eq("https://example.com/projects/test_project/issue") + end + end + + describe ".change_service" do + before do + stub_put("/projects/3/services/redmine", "service") + @service = Gitlab.change_service(3, :redmine, new_issue_url: 'https://example.com/projects/test_project/issues/new', + project_url: 'https://example.com/projects/test_project/issues', + issues_url: 'https://example.com/issues/:id') + end + + it "should get the correct resource" do + body = {new_issue_url: 'https://example.com/projects/test_project/issues/new', + project_url: 'https://example.com/projects/test_project/issues', + issues_url: 'https://example.com/issues/:id'} + expect(a_put("/projects/3/services/redmine").with(body: body)).to have_been_made + end + + it "should return information about a new service" do + expect(@service).to be_truthy + end + end + + describe ".delete_servoce" do + before do + stub_delete("/projects/3/services/redmine", "service") + @service = Gitlab.delete_service(3, :redmine) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/services/redmine")).to have_been_made + end + + it "should return information about a deleted service" do + expect(@service).to be_truthy + end + end +end diff --git a/spec/gitlab/client/snippets_spec.rb b/spec/gitlab/client/snippets_spec.rb new file mode 100644 index 0000000..e6c94b1 --- /dev/null +++ b/spec/gitlab/client/snippets_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".snippets" do + before do + stub_get("/projects/3/snippets", "snippets") + @snippets = Gitlab.snippets(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets")).to have_been_made + end + + it "should return a paginated response of project's snippets" do + expect(@snippets).to be_a Gitlab::PaginatedResponse + expect(@snippets.first.file_name).to eq("mailer_test.rb") + end + end + + describe ".snippet" do + before do + stub_get("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".create_snippet" do + before do + stub_post("/projects/3/snippets", "snippet") + @snippet = Gitlab.create_snippet(3, title: 'API', file_name: 'api.rb', code: 'code') + end + + it "should get the correct resource" do + body = { title: 'API', file_name: 'api.rb', code: 'code' } + expect(a_post("/projects/3/snippets").with(body: body)).to have_been_made + end + + it "should return information about a new snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".edit_snippet" do + before do + stub_put("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.edit_snippet(3, 1, file_name: 'mailer_test.rb') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/snippets/1"). + with(body: { file_name: 'mailer_test.rb' })).to have_been_made + end + + it "should return information about an edited snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".delete_snippet" do + before do + stub_delete("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.delete_snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a deleted snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".snippet_content" do + before do + stub_get("/projects/3/snippets/1/raw", "snippet_content") + @snippet_content = Gitlab.snippet_content(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/1/raw")).to have_been_made + end + + it "should return raw content of a snippet" do + expect(@snippet_content).to eq("#!/usr/bin/env ruby\n\nputs \"Cool snippet!\"\n") + end + end +end diff --git a/spec/gitlab/client/system_hooks_spec.rb b/spec/gitlab/client/system_hooks_spec.rb new file mode 100644 index 0000000..e808435 --- /dev/null +++ b/spec/gitlab/client/system_hooks_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :system_hooks } + it { should respond_to :add_system_hook } + it { should respond_to :system_hook } + it { should respond_to :delete_system_hook } + + describe ".hooks" do + before do + stub_get("/hooks", "system_hooks") + @hooks = Gitlab.hooks + end + + it "should get the correct resource" do + expect(a_get("/hooks")).to have_been_made + end + + it "should return a paginated response of system hooks" do + expect(@hooks).to be_a Gitlab::PaginatedResponse + expect(@hooks.first.url).to eq("http://example.com/hook") + end + end + + describe ".add_hook" do + before do + stub_post("/hooks", "system_hook") + @hook = Gitlab.add_hook("http://example.com/hook") + end + + it "should get the correct resource" do + expect(a_post("/hooks")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end + + describe ".hook" do + before do + stub_get("/hooks/3", "system_hook") + @hook = Gitlab.hook(3) + end + + it "should get the correct resource" do + expect(a_get("/hooks/3")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end + + describe ".delete_hook" do + before do + stub_delete("/hooks/3", "system_hook") + @hook = Gitlab.delete_hook(3) + end + + it "should get the correct resource" do + expect(a_delete("/hooks/3")).to have_been_made + end + + it "should return information about a deleted system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end +end diff --git a/spec/gitlab/client/tags_spec.rb b/spec/gitlab/client/tags_spec.rb new file mode 100644 index 0000000..1a585e7 --- /dev/null +++ b/spec/gitlab/client/tags_spec.rb @@ -0,0 +1,109 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_tags } + it { should respond_to :repo_tag } + it { should respond_to :repo_create_tag } + it { should respond_to :repo_delete_tag } + it { should respond_to :repo_create_release } + it { should respond_to :repo_update_release } + + describe '.tags' do + before do + stub_get("/projects/3/repository/tags", "tags") + @tags = Gitlab.tags(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tags")).to have_been_made + end + + it "should return a paginated response of repository tags" do + expect(@tags).to be_a Gitlab::PaginatedResponse + expect(@tags.map(&:name)).to eq(%w[0.0.2 0.0.1]) + end + end + + describe ".tag" do + before do + stub_get("/projects/3/repository/tags/0.0.1", "tag") + @tag = Gitlab.tag(3, "0.0.1") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tags/0.0.1")).to have_been_made + end + + it "should return information about a repository tag" do + expect(@tag.name).to eq("0.0.1") + end + end + + describe ".create_tag" do + before do + stub_post("/projects/3/repository/tags", "tag_create") + @tag = Gitlab.create_tag(3, "0.0.1", "master", 'this tag is annotated', 'and it has release notes') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags")).to have_been_made + end + + it "should return information about a new repository tag" do + expect(@tag.name).to eq("0.0.1") + expect(@tag.message).to eq('this tag is annotated') + end + + it "should return detailed information" do + expect(@tag.release.description).to eq('and it has release notes') + end + end + + describe ".delete_tag" do + before do + stub_delete("/projects/3/repository/tags/0.0.1", "tag_delete") + @tag = Gitlab.delete_tag(3, "0.0.1") + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/repository/tags/0.0.1")).to have_been_made + end + + it "should return information about the deleted repository tag" do + expect(@tag.tag_name).to eq("0.0.1") + end + end + + describe ".create_release" do + before do + stub_post("/projects/3/repository/tags/0.0.1/release", "release_create") + @tag = Gitlab.create_release(3, "0.0.1", "Amazing release. Wow") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags/0.0.1/release")).to have_been_made + end + + it "should return information about the tag and the release" do + expect(@tag.tag_name).to eq("0.0.1") + expect(@tag.description).to eq("Amazing release. Wow") + end + end + + describe ".update_release" do + before do + stub_put("/projects/3/repository/tags/0.0.1/release", "release_update") + @tag = Gitlab.update_release(3, "0.0.1", 'Amazing release. Wow') + end + + it "should update the correct resource" do + expect(a_put("/projects/3/repository/tags/0.0.1/release")).to have_been_made + end + + it "should return information about the tag" do + expect(@tag.tag_name).to eq("0.0.1") + expect(@tag.description).to eq('Amazing release. Wow') + end + end + +end diff --git a/spec/gitlab/client/users_spec.rb b/spec/gitlab/client/users_spec.rb new file mode 100644 index 0000000..815aabb --- /dev/null +++ b/spec/gitlab/client/users_spec.rb @@ -0,0 +1,418 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".users" do + before do + stub_get("/users", "users") + @users = Gitlab.users + end + + it "should get the correct resource" do + expect(a_get("/users")).to have_been_made + end + + it "should return a paginated response of users" do + expect(@users).to be_a Gitlab::PaginatedResponse + expect(@users.first.email).to eq("john@example.com") + end + end + + describe ".user" do + context "with user ID passed" do + before do + stub_get("/users/1", "user") + @user = Gitlab.user(1) + end + + it "should get the correct resource" do + expect(a_get("/users/1")).to have_been_made + end + + it "should return information about a user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "without user ID passed" do + before do + stub_get("/user", "user") + @user = Gitlab.user + end + + it "should get the correct resource" do + expect(a_get("/user")).to have_been_made + end + + it "should return information about an authorized user" do + expect(@user.email).to eq("john@example.com") + end + end + end + + describe ".create_user" do + context "when successful request" do + before do + stub_post("/users", "user") + @user = Gitlab.create_user("email", "pass") + end + + it "should get the correct resource" do + body = { email: "email", password: "pass", name: "email" } + expect(a_post("/users").with(body: body)).to have_been_made + end + + it "should return information about a created user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "when bad request" do + it "should throw an exception" do + stub_post("/users", "error_already_exists", 409) + expect do + Gitlab.create_user("email", "pass") + end.to raise_error(Gitlab::Error::Conflict, "Server responded with code 409, message: 409 Already exists. Request URI: #{Gitlab.endpoint}/users") + end + end + end + + describe ".create_user_with_userame" do + context "when successful request" do + before do + stub_post("/users", "user") + @user = Gitlab.create_user("email", "pass", "username") + end + + it "should get the correct resource" do + body = { email: "email", password: "pass", username: "username" } + expect(a_post("/users").with(body: body)).to have_been_made + end + + it "should return information about a created user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "when bad request" do + it "should throw an exception" do + stub_post("/users", "error_already_exists", 409) + expect do + Gitlab.create_user("email", "pass", "username") + end.to raise_error(Gitlab::Error::Conflict, "Server responded with code 409, message: 409 Already exists. Request URI: #{Gitlab.endpoint}/users") + end + end + end + + describe ".edit_user" do + before do + @options = { name: "Roberto" } + stub_put("/users/1", "user").with(body: @options) + @user = Gitlab.edit_user(1, @options) + end + + it "should get the correct resource" do + expect(a_put("/users/1").with(body: @options)).to have_been_made + end + end + + describe ".delete_user" do + before do + stub_delete("/users/1", "user") + @user = Gitlab.delete_user(1) + end + + it "should get the correct resource" do + expect(a_delete("/users/1")).to have_been_made + end + + it "should return information about a deleted user" do + expect(@user.email).to eq("john@example.com") + end + end + + describe ".block_user" do + before do + stub_post("/users/1/block", "user_block_unblock") + @result = Gitlab.block_user(1) + end + + it "should get the correct resource" do + expect(a_post("/users/1/block")).to have_been_made + end + + it "should return boolean" do + expect(@result).to eq(true) + end + end + + describe ".unblock_user" do + before do + stub_post("/users/1/unblock", "user_block_unblock") + @result = Gitlab.unblock_user(1) + end + + it "should get the correct resource" do + expect(a_post("/users/1/unblock")).to have_been_made + end + + it "should return boolean" do + expect(@result).to eq(true) + end + end + + describe ".session" do + after do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end + + before do + stub_request(:post, "#{Gitlab.endpoint}/session"). + to_return(body: load_fixture('session'), status: 200) + @session = Gitlab.session("email", "pass") + end + + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + Gitlab.endpoint = nil + expect do + Gitlab.session("email", "pass") + end.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when private_token is not set" do + it "should not raise Error::MissingCredentials" do + Gitlab.private_token = nil + expect { Gitlab.session("email", "pass") }.to_not raise_error + end + end + + context "when endpoint is set" do + it "should get the correct resource" do + expect(a_request(:post, "#{Gitlab.endpoint}/session")).to have_been_made + end + + it "should return information about a created session" do + expect(@session.email).to eq("john@example.com") + expect(@session.private_token).to eq("qEsq1pt6HJPaNciie3MG") + end + end + end + + describe ".ssh_keys" do + context "with user ID passed" do + before do + stub_get("/users/1/keys", "keys") + @keys = Gitlab.ssh_keys({ user_id: 1 }) + end + + it "should get the correct resource" do + expect(a_get("/users/1/keys")).to have_been_made + end + + it "should return a paginated response of SSH keys" do + expect(@keys).to be_a Gitlab::PaginatedResponse + expect(@keys.first.title).to eq("narkoz@helium") + end + end + + context "without user ID passed" do + before do + stub_get("/user/keys", "keys") + @keys = Gitlab.ssh_keys + end + + it "should get the correct resource" do + expect(a_get("/user/keys")).to have_been_made + end + + it "should return a paginated response of SSH keys" do + expect(@keys).to be_a Gitlab::PaginatedResponse + expect(@keys.first.title).to eq("narkoz@helium") + end + end + end + + describe ".ssh_key" do + before do + stub_get("/user/keys/1", "key") + @key = Gitlab.ssh_key(1) + end + + it "should get the correct resource" do + expect(a_get("/user/keys/1")).to have_been_made + end + + it "should return information about an SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".create_ssh_key" do + before do + stub_post("/user/keys", "key") + @key = Gitlab.create_ssh_key("title", "body") + end + + it "should get the correct resource" do + body = { title: "title", key: "body" } + expect(a_post("/user/keys").with(body: body)).to have_been_made + end + + it "should return information about a created SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".delete_ssh_key" do + before do + stub_delete("/user/keys/1", "key") + @key = Gitlab.delete_ssh_key(1) + end + + it "should get the correct resource" do + expect(a_delete("/user/keys/1")).to have_been_made + end + + it "should return information about a deleted SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".emails" do + describe "without user ID" do + before do + stub_get("/user/emails", "user_emails") + @emails = Gitlab.emails + end + + it "should get the correct resource" do + expect(a_get("/user/emails")).to have_been_made + end + + it "should return a information about a emails of user" do + email = @emails.first + expect(email.id).to eq 1 + expect(email.email).to eq("email@example.com") + end + end + + describe "with user ID" do + before do + stub_get("/users/2/emails", "user_emails") + @emails = Gitlab.emails(2) + end + + it "should get the correct resource" do + expect(a_get("/users/2/emails")).to have_been_made + end + + it "should return a information about a emails of user" do + email = @emails.first + expect(email.id).to eq 1 + expect(email.email).to eq("email@example.com") + end + end + end + + describe ".email" do + before do + stub_get("/user/emails/2", "user_email") + @email = Gitlab.email(2) + end + + it "should get the correct resource" do + expect(a_get("/user/emails/2")).to have_been_made + end + + it "should return a information about a email of user" do + expect(@email.id).to eq 1 + expect(@email.email).to eq("email@example.com") + end + end + + describe ".add_email" do + describe "without user ID" do + before do + stub_post("/user/emails", "user_email") + @email = Gitlab.add_email("email@example.com") + end + + it "should get the correct resource" do + body = { email: "email@example.com" } + expect(a_post("/user/emails").with(body: body)).to have_been_made + end + + it "should return information about a new email" do + expect(@email.id).to eq(1) + expect(@email.email).to eq("email@example.com") + end + end + + describe "with user ID" do + before do + stub_post("/users/2/emails", "user_email") + @email = Gitlab.add_email("email@example.com", 2) + end + + it "should get the correct resource" do + body = { email: "email@example.com" } + expect(a_post("/users/2/emails").with(body: body)).to have_been_made + end + + it "should return information about a new email" do + expect(@email.id).to eq(1) + expect(@email.email).to eq("email@example.com") + end + end + end + + describe ".delete_email" do + describe "without user ID" do + before do + stub_delete("/user/emails/1", "user_email") + @email = Gitlab.delete_email(1) + end + + it "should get the correct resource" do + expect(a_delete("/user/emails/1")).to have_been_made + end + + it "should return information about a deleted email" do + expect(@email).to be_truthy + end + end + + describe "with user ID" do + before do + stub_delete("/users/2/emails/1", "user_email") + @email = Gitlab.delete_email(1, 2) + end + + it "should get the correct resource" do + expect(a_delete("/users/2/emails/1")).to have_been_made + end + + it "should return information about a deleted email" do + expect(@email).to be_truthy + end + end + end + + describe ".user_search" do + before do + stub_get("/users?search=User", "user_search") + @users = Gitlab.user_search('User') + end + + it "should get the correct resource" do + expect(a_get("/users?search=User")).to have_been_made + end + + it "should return an array of users found" do + expect(@users.first.id).to eq(1) + expect(@users.last.id).to eq(2) + end + end +end diff --git a/spec/gitlab/error_spec.rb b/spec/gitlab/error_spec.rb new file mode 100644 index 0000000..7a9e47e --- /dev/null +++ b/spec/gitlab/error_spec.rb @@ -0,0 +1,45 @@ +require "spec_helper" + +describe Gitlab::Error do + describe "#handle_message" do + require "stringio" + + before do + request_object = HTTParty::Request.new(Net::HTTP::Get, '/') + response_object = Net::HTTPOK.new('1.1', 200, 'OK') + body = StringIO.new("{foo:'bar'}") + def body.message; self.string; end + + parsed_response = lambda { body } + response_object['last-modified'] = Date.new(2010, 1, 15).to_s + response_object['content-length'] = "1024" + + response = HTTParty::Response.new(request_object, response_object, parsed_response, body: body) + @error = Gitlab::Error::ResponseError.new(response) + + @array = Array.new(['First message.', 'Second message.']) + @obj_h = Gitlab::ObjectifiedHash.new(user: ['not set'], + password: ['too short'], + embed_entity: { foo: ['bar'], sna: ['fu'] }) + end + + context "when passed an ObjectifiedHash" do + it "should return a joined string of error messages sorted by key" do + expect(@error.send(:handle_message, @obj_h)).to eq("'embed_entity' (foo: bar) (sna: fu), 'password' too short, 'user' not set") + end + end + + context "when passed an Array" do + it "should return a joined string of messages" do + expect(@error.send(:handle_message, @array)).to eq("First message. Second message.") + end + end + + context "when passed a String" do + it "should return the String untouched" do + error = 'this is an error string' + expect(@error.send(:handle_message, error)).to eq('this is an error string') + end + end + end +end diff --git a/spec/gitlab/file_response_spec.rb b/spec/gitlab/file_response_spec.rb new file mode 100644 index 0000000..455d47d --- /dev/null +++ b/spec/gitlab/file_response_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::FileResponse do + before do + @file_response = Gitlab::FileResponse.new StringIO.new("", 'rb+') + end + + context '.empty?' do + it "shoudl return false" do + expect(@file_response.empty?).to be false + end + end + + context '.to_hash' do + it "should have `filename` key and `data` key" do + h = @file_response.to_hash + expect(h.has_key?(:filename)).to be_truthy + expect(h.has_key?(:data)).to be_truthy + end + end + + context '.parse_headers!' do + it "should parse headers" do + @file_response.parse_headers!('Content-Disposition' => 'attachment; filename=artifacts.zip') + expect(@file_response.filename).to eq "artifacts.zip" + end + + it "should handle quoted filenames" do + @file_response.parse_headers!('Content-Disposition' => 'attachment; filename="artifacts.zip"') + expect(@file_response.filename).to eq "artifacts.zip" + end + end +end diff --git a/spec/gitlab/help_spec.rb b/spec/gitlab/help_spec.rb new file mode 100644 index 0000000..b8d2d7c --- /dev/null +++ b/spec/gitlab/help_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe Gitlab::Help do + describe ".ri_cmd" do + context "ri command found" do + it "should return the path to RI" do + allow(Gitlab::Help).to receive(:`).with(/which ri/).and_return('/usr/bin/ri') + expect(Gitlab::Help.ri_cmd).to eq('/usr/bin/ri') + end + end + + context "ri command NOT found" do + it "should raise" do + allow(Gitlab::Help).to receive(:`).with(/which ri/).and_return('') + expect { Gitlab::Help.ri_cmd }.to raise_error RuntimeError + end + end + end + + describe ".change_help_output!" do + before do + @cmd = "create_branch" + @help_output = "Gitlab.#{@cmd}(4, 'new-branch', 'master')" + @help_output_with_options = "Gitlab.groups({ per_page: 3 })" + end + it "should return a String of modified output" do + Gitlab::Help.change_help_output! @cmd, @help_output + expect(@help_output).to eq("Gitlab.create_branch 4 'new-branch' 'master'") + end + it "should format options hash and return a String of modified output" do + Gitlab::Help.change_help_output! 'groups', @help_output_with_options + expect(@help_output_with_options).to eq("Gitlab.groups \"{ per_page: 3 }\"") + end + end + + describe ".namespace" do + before do + @cmd = 'create_tag' + @namespace = Gitlab::Help.namespace @cmd + end + it "should return the full namespace for a command" do + expect(@namespace).to be_a String + expect(@namespace).to eq("Gitlab::Client::Tags.#{@cmd}") + end + end +end diff --git a/spec/gitlab/objectified_hash_spec.rb b/spec/gitlab/objectified_hash_spec.rb new file mode 100644 index 0000000..c3f08eb --- /dev/null +++ b/spec/gitlab/objectified_hash_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::ObjectifiedHash do + before do + @hash = { a: 1, b: 2, 'string' => 'string', symbol: :symbol } + @oh = Gitlab::ObjectifiedHash.new @hash + end + + it "should objectify hash" do + expect(@oh.a).to eq(@hash[:a]) + expect(@oh.b).to eq(@hash[:b]) + end + + describe "#to_hash" do + it "should return an original hash" do + expect(@oh.to_hash).to eq(@hash) + end + + it "should have an alias #to_h" do + expect(@oh.respond_to?(:to_h)).to be_truthy + end + end + + describe "#inspect" do + it "should return a formatted string" do + pretty_string = "#<#{@oh.class.name}:#{@oh.object_id} {hash: #{@hash}}" + expect(@oh.inspect).to eq(pretty_string) + end + end + + describe "#respond_to" do + it "should return true for methods this object responds to through method_missing as sym" do + expect(@oh.respond_to?(:a)).to be_truthy + end + + it "should return true for methods this object responds to through method_missing as string" do + expect(@oh.respond_to?('string')).to be_truthy + end + + it "should not care if you use a string or symbol to reference a method" do + expect(@oh.respond_to?(:string)).to be_truthy + end + + it "should not care if you use a string or symbol to reference a method" do + expect(@oh.respond_to?('symbol')).to be_truthy + end + end +end diff --git a/spec/gitlab/page_links_spec.rb b/spec/gitlab/page_links_spec.rb new file mode 100644 index 0000000..973c9b9 --- /dev/null +++ b/spec/gitlab/page_links_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe Gitlab::PageLinks do + before do + @page_links = Gitlab::PageLinks.new('Link' => "; rel=\"first\", ; rel=\"last\", ; rel=\"prev\", ; rel=\"next\"") + end + + context '.extract_links' do + it 'should extract link header appropriately' do + expect(@page_links.last).to eql 'http://example.com/api/v3/projects?page=20&per_page=5' + expect(@page_links.first).to eql 'http://example.com/api/v3/projects?page=1&per_page=5' + expect(@page_links.next).to eql 'http://example.com/api/v3/projects?page=9&per_page=5' + expect(@page_links.prev).to eql 'http://example.com/api/v3/projects?page=7&per_page=5' + end + end +end diff --git a/spec/gitlab/paginated_response_spec.rb b/spec/gitlab/paginated_response_spec.rb new file mode 100644 index 0000000..72c17c8 --- /dev/null +++ b/spec/gitlab/paginated_response_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Gitlab::PaginatedResponse do + before do + array = [1, 2, 3, 4] + @paginated_response = Gitlab::PaginatedResponse.new array + end + + it "should respond to *_page and has_*_page methods" do + expect(@paginated_response).to respond_to :first_page + expect(@paginated_response).to respond_to :last_page + expect(@paginated_response).to respond_to :next_page + expect(@paginated_response).to respond_to :prev_page + expect(@paginated_response).to respond_to :has_first_page? + expect(@paginated_response).to respond_to :has_last_page? + expect(@paginated_response).to respond_to :has_next_page? + expect(@paginated_response).to respond_to :has_prev_page? + end + + context '.parse_headers!' do + it "should parse headers" do + @paginated_response.parse_headers!('Link' => "; rel=\"first\", ; rel=\"last\"") + client = @paginated_response.client = double('client') + first_page_response = double('first_page_response') + last_page_response = double('last_page_response') + allow(client).to receive(:endpoint).and_return("http://example.com/api/v3") + allow(client).to receive(:get).with("/projects?page=1&per_page=5").and_return(first_page_response) + allow(client).to receive(:get).with("/projects?page=20&per_page=5").and_return(last_page_response) + expect(@paginated_response.has_first_page?).to be true + expect(@paginated_response.has_last_page?).to be true + expect(@paginated_response.has_next_page?).to be false + expect(@paginated_response.has_prev_page?).to be false + expect(@paginated_response.first_page).to be first_page_response + expect(@paginated_response.last_page).to be last_page_response + expect(@paginated_response.next_page).to be_nil + expect(@paginated_response.prev_page).to be_nil + end + end + + context '.each_page' do + it "should iterate pages" do + next_page = double('next_page') + allow(@paginated_response).to receive(:has_next_page?).and_return(true) + allow(@paginated_response).to receive(:next_page).and_return(next_page) + allow(next_page).to receive(:has_next_page?).and_return(false) + expect { |b| @paginated_response.each_page(&b) }.to yield_successive_args(@paginated_response, next_page) + end + end + + context '.auto_paginate' do + it "should returns an array if block is not given" do + next_page = double('next_page') + allow(@paginated_response).to receive(:has_next_page?).and_return(true) + allow(@paginated_response).to receive(:next_page).and_return(next_page) + allow(next_page).to receive(:has_next_page?).and_return(false) + allow(next_page).to receive(:to_ary).and_return([5, 6, 7, 8]) + expect(@paginated_response.auto_paginate).to contain_exactly(1, 2, 3, 4, 5, 6, 7, 8) + end + end +end diff --git a/spec/gitlab/request_spec.rb b/spec/gitlab/request_spec.rb new file mode 100644 index 0000000..111a6f4 --- /dev/null +++ b/spec/gitlab/request_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Gitlab::Request do + it { should respond_to :get } + it { should respond_to :post } + it { should respond_to :put } + it { should respond_to :delete } + before do + @request = Gitlab::Request.new + end + + describe ".default_options" do + it "should have default values" do + default_options = Gitlab::Request.default_options + expect(default_options).to be_a Hash + expect(default_options[:parser]).to be_a Proc + expect(default_options[:format]).to eq(:json) + expect(default_options[:headers]).to eq('Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded') + expect(default_options[:default_params]).to be_nil + end + end + + describe ".parse" do + it "should return ObjectifiedHash" do + body = JSON.unparse(a: 1, b: 2) + expect(Gitlab::Request.parse(body)).to be_an Gitlab::ObjectifiedHash + expect(Gitlab::Request.parse("true")).to be true + expect(Gitlab::Request.parse("false")).to be false + + expect { Gitlab::Request.parse("string") }.to raise_error(Gitlab::Error::Parsing) + end + end + + describe "#set_request_defaults" do + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + @request.endpoint = nil + expect do + @request.set_request_defaults + end.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when endpoint is set" do + before(:each) do + @request.endpoint = 'http://rabbit-hole.example.org' + end + + it "should set default_params" do + @request.set_request_defaults('sudoer') + expect(Gitlab::Request.default_params).to eq(sudo: 'sudoer') + end + end + end + + describe "#set_authorization_header" do + it "should raise MissingCredentials when auth_token and private_token are not set" do + expect do + @request.send(:set_authorization_header, {}) + end.to raise_error(Gitlab::Error::MissingCredentials) + end + + it "should set the correct header when given a private_token" do + @request.private_token = 'ys9BtunN3rDKbaJCYXaN' + expect(@request.send(:set_authorization_header, {})).to eq("PRIVATE-TOKEN" => 'ys9BtunN3rDKbaJCYXaN') + end + + it "should set the correct header when setting an auth_token via the private_token config option" do + @request.private_token = '3225e2804d31fea13fc41fc83bffef00cfaedc463118646b154acc6f94747603' + expect(@request.send(:set_authorization_header, {})).to eq("Authorization" => "Bearer 3225e2804d31fea13fc41fc83bffef00cfaedc463118646b154acc6f94747603") + end + end +end diff --git a/spec/gitlab/shell_history_spec.rb b/spec/gitlab/shell_history_spec.rb new file mode 100644 index 0000000..897f335 --- /dev/null +++ b/spec/gitlab/shell_history_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' +require 'tempfile' + +describe Gitlab::Shell::History do + context 'saving to a file' do + before do + @file = Tempfile.new('.gitlab_shell_history') + @history = Gitlab::Shell::History.new(file_path: @file.path) + end + + after { @file.close(true) } + + it 'saves the lines' do + @history << 'party on, dudes' + @history << 'be excellent to each other' + @history.save + expect(File.read @file.path). + to eq("party on, dudes\nbe excellent to each other\n") + end + + it 'has the lines' do + @history << 'party on, dudes' + @history << 'be excellent to each other' + expect(@history.lines). + to eq(["party on, dudes", "be excellent to each other"]) + end + + it 'limits the lines to GITLAB_HISTFILESIZE' do + ENV['GITLAB_HISTFILESIZE'] = '2' + @history << 'bogus' + @history << 'party on, dudes' + @history << 'be excellent to each other' + @history.save + expect(@history.lines). + to eq(["party on, dudes", "be excellent to each other"]) + expect(File.read @file.path). + to eq("party on, dudes\nbe excellent to each other\n") + end + end + + context 'loading a file' do + before do + @file = load_fixture('shell_history') + @history = Gitlab::Shell::History.new(file_path: @file.path) + end + + it 'has the lines' do + @history.load + expect(@history.lines). + to eq(["party on, dudes", "be excellent to each other"]) + end + end +end diff --git a/spec/gitlab/shell_spec.rb b/spec/gitlab/shell_spec.rb new file mode 100644 index 0000000..ac6f318 --- /dev/null +++ b/spec/gitlab/shell_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::Shell do + before do + Gitlab::Shell.setup + end + + describe ".execute" do + context "invalid command" do + it "should raise" do + expect { Gitlab::Shell.execute 'foobar', [] }.to raise_error(RuntimeError) + end + end + end + + describe ".history" do + before do + @history = Gitlab::Shell.history + end + + it "should return a Gitlab::Shell::History instance" do + expect(@history).to be_a Gitlab::Shell::History + end + it "should respond to :save" do + expect(@history).to respond_to :save + end + it "should respond to :load" do + expect(@history).to respond_to :load + end + it "should respond to :<<" do + expect(@history).to respond_to :<< + end + end + + describe ".setup" do + it "should set the Readline completion_proc" do + completion = Readline.completion_proc + expect(completion).to be_truthy + expect(completion).to be_a Proc + end + it "should set the Readline completion_append_character" do + completion_character = Readline.completion_append_character + expect(completion_character).to eq(' ') + end + end + + describe ".completion" do + before do + @comp = Gitlab::Shell.completion + end + it "should return a Proc object" do + expect(@comp).to be_a Proc + end + context "called with an argument" do + it "should return an Array of matching commands" do + completed_cmds = @comp.call 'group' + expect(completed_cmds).to be_a Array + expect(completed_cmds.sort).to eq(%w(group group_members group_projects group_search groups)) + end + end + end + + describe ".parse_input" do + context "with arguments" do + it "should set command & arguments" do + Gitlab::Shell.parse_input('create_branch 1 "api" "master"') + expect(Gitlab::Shell.command).to eq('create_branch') + expect(Gitlab::Shell.arguments).to eq(%w(1 api master)) + end + end + + context "without arguments" do + it 'should set command & empty arguments' do + Gitlab::Shell.parse_input('exit') + expect(Gitlab::Shell.command).to eq('exit') + expect(Gitlab::Shell.arguments).to be_empty + end + end + end +end diff --git a/spec/gitlab_spec.rb b/spec/gitlab_spec.rb new file mode 100644 index 0000000..b769f40 --- /dev/null +++ b/spec/gitlab_spec.rb @@ -0,0 +1,97 @@ +require 'spec_helper' + +describe Gitlab do + after { Gitlab.reset } + + describe ".client" do + it "should be a Gitlab::Client" do + expect(Gitlab.client).to be_a Gitlab::Client + end + + it "should not override each other" do + client1 = Gitlab.client(endpoint: 'https://api1.example.com', private_token: '001') + client2 = Gitlab.client(endpoint: 'https://api2.example.com', private_token: '002') + expect(client1.endpoint).to eq('https://api1.example.com') + expect(client2.endpoint).to eq('https://api2.example.com') + expect(client1.private_token).to eq('001') + expect(client2.private_token).to eq('002') + end + + it "should set private_token to the auth_token when provided" do + client = Gitlab.client(endpoint: 'https://api2.example.com', auth_token: '3225e2804d31fea13fc41fc83bffef00cfaedc463118646b154acc6f94747603') + expect(client.private_token).to eq('3225e2804d31fea13fc41fc83bffef00cfaedc463118646b154acc6f94747603') + end + end + + describe ".actions" do + it "should return an array of client methods" do + actions = Gitlab.actions + expect(actions).to be_an Array + expect(actions.first).to be_a Symbol + expect(actions.sort.first).to eq(:accept_merge_request) + end + end + + describe ".endpoint=" do + it "should set endpoint" do + Gitlab.endpoint = 'https://api.example.com' + expect(Gitlab.endpoint).to eq('https://api.example.com') + end + end + + describe ".private_token=" do + it "should set private_token" do + Gitlab.private_token = 'secret' + expect(Gitlab.private_token).to eq('secret') + end + end + + describe ".auth_token=" do + it "should set auth_token", focus: true do + Gitlab.auth_token = 'auth_secret' + expect(Gitlab.private_token).to eq('auth_secret') + end + end + + describe ".sudo=" do + it "should set sudo" do + Gitlab.sudo = 'user' + expect(Gitlab.sudo).to eq('user') + end + end + + describe ".user_agent" do + it "should return default user_agent" do + expect(Gitlab.user_agent).to eq(Gitlab::Configuration::DEFAULT_USER_AGENT) + end + end + + describe ".user_agent=" do + it "should set user_agent" do + Gitlab.user_agent = 'Custom User Agent' + expect(Gitlab.user_agent).to eq('Custom User Agent') + end + end + + describe ".configure" do + Gitlab::Configuration::VALID_OPTIONS_KEYS.each do |key| + it "should set #{key}" do + Gitlab.configure do |config| + config.send("#{key}=", key) + expect(Gitlab.send(key)).to eq(key) + end + end + end + end + + describe ".http_proxy" do + it "delegates the method to Gitlab::Request" do + Gitlab.endpoint = 'https://api.example.com' + request = class_spy(Gitlab::Request).as_stubbed_const + + Gitlab.http_proxy('fazbearentertainment.com', 1987, 'ffazbear', 'itsme') + expect(request).to have_received(:http_proxy). + with('fazbearentertainment.com', 1987, 'ffazbear', 'itsme') + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..1ed7ddb --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,74 @@ +require 'rspec' +require 'webmock/rspec' + +require File.expand_path('../../lib/gitlab', __FILE__) +require File.expand_path('../../lib/gitlab/cli', __FILE__) + +def capture_output + out = StringIO.new + $stdout = out + $stderr = out + yield + $stdout = STDOUT + $stderr = STDERR + out.string +end + +def load_fixture(name) + File.new(File.dirname(__FILE__) + "/fixtures/#{name}.json") +end + +RSpec.configure do |config| + config.before(:all) do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end +end + +# GET +def stub_get(path, fixture, status_code=200) + stub_request(:get, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: load_fixture(fixture), status: status_code) +end + +def a_get(path) + a_request(:get, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }) +end + +# POST +def stub_post(path, fixture, status_code=200) + stub_request(:post, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: load_fixture(fixture), status: status_code) +end + +def a_post(path) + a_request(:post, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }) +end + +# PUT +def stub_put(path, fixture) + stub_request(:put, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: load_fixture(fixture)) +end + +def a_put(path) + a_request(:put, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }) +end + +# DELETE +def stub_delete(path, fixture) + stub_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }). + to_return(body: load_fixture(fixture)) +end + +def a_delete(path) + a_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(headers: { 'PRIVATE-TOKEN' => Gitlab.private_token }) +end