This commit is contained in:
402
node_modules/decap-cms-backend-gitlab/CHANGELOG.md
generated
vendored
Normal file
402
node_modules/decap-cms-backend-gitlab/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.2.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.2.1...decap-cms-backend-gitlab@3.2.2) (2024-08-13)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "Update dependencies (#7264)" ([22d483a](https://github.com/decaporg/decap-cms/commit/22d483a5b0c654071ae05735ac4f49abdc13d38c)), closes [#7264](https://github.com/decaporg/decap-cms/issues/7264)
|
||||
|
||||
## [3.2.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.2.0...decap-cms-backend-gitlab@3.2.1) (2024-08-13)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [3.2.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.3...decap-cms-backend-gitlab@3.2.0) (2024-08-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend:** allow a custom API root for backend ([#7214](https://github.com/decaporg/decap-cms/issues/7214)) ([fae3e05](https://github.com/decaporg/decap-cms/commit/fae3e057f898f60fdbe80091acc833d6ac92696e)), closes [#7168](https://github.com/decaporg/decap-cms/issues/7168)
|
||||
|
||||
## [3.1.3](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.2...decap-cms-backend-gitlab@3.1.3) (2024-04-03)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [3.1.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.1...decap-cms-backend-gitlab@3.1.2) (2024-03-21)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [3.1.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.0-beta.1...decap-cms-backend-gitlab@3.1.1) (2024-02-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- gitlab pkce auth error ([#7110](https://github.com/decaporg/decap-cms/issues/7110)) ([bcd58d6](https://github.com/decaporg/decap-cms/commit/bcd58d6e117b4654b3e0dca173f7f8aaca8dabdf))
|
||||
|
||||
# [3.1.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.0-beta.1...decap-cms-backend-gitlab@3.1.0) (2024-02-01)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [3.1.0-beta.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.0-beta.0...decap-cms-backend-gitlab@3.1.0-beta.1) (2024-01-31)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [3.1.0-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.1.0...decap-cms-backend-gitlab@3.1.0-beta.0) (2023-10-20)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "chore(release): publish" ([b89fc89](https://github.com/decaporg/decap-cms/commit/b89fc894dfbb5f4136b2e5427fd25a29378a58c6))
|
||||
|
||||
## [3.0.2](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.0.1...decap-cms-backend-gitlab@3.0.2) (2023-10-13)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [3.0.1](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@3.0.0...decap-cms-backend-gitlab@3.0.1) (2023-08-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- update peer dependencies ([#6886](https://github.com/decaporg/decap-cms/issues/6886)) ([e580ce5](https://github.com/decaporg/decap-cms/commit/e580ce52ce5f80fa040e8fbcab7fed0744f4f695))
|
||||
|
||||
# [3.0.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@2.14.0...decap-cms-backend-gitlab@3.0.0) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.14.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@2.14.0-beta.0...decap-cms-backend-gitlab@2.14.0) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# 2.14.0-beta.0 (2023-08-18)
|
||||
|
||||
### Features
|
||||
|
||||
- rename packages ([#6863](https://github.com/decaporg/decap-cms/issues/6863)) ([d515e7b](https://github.com/decaporg/decap-cms/commit/d515e7bd33216a775d96887b08c4f7b1962941bb))
|
||||
|
||||
## [2.13.1-beta.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@2.13.0...decap-cms-backend-gitlab@2.13.1-beta.0) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.13.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@2.12.0...decap-cms-backend-gitlab@2.13.0) (2021-12-28)
|
||||
|
||||
### Features
|
||||
|
||||
- **backend-gitlab:** initial GraphQL support ([#6059](https://github.com/decaporg/decap-cms/issues/6059)) ([1523a41](https://github.com/decaporg/decap-cms/commit/1523a4140a3d2f4cc01a1548514ae17bc1ad504e))
|
||||
|
||||
# [2.12.0](https://github.com/decaporg/decap-cms/compare/decap-cms-backend-gitlab@2.11.4...decap-cms-backend-gitlab@2.12.0) (2021-10-18)
|
||||
|
||||
### Features
|
||||
|
||||
- display author of changes in workflow tab ([#5780](https://github.com/decaporg/decap-cms/issues/5780)) ([3f607e4](https://github.com/decaporg/decap-cms/commit/3f607e41d9c4d8fe5329a9ab6841cada7742825e))
|
||||
|
||||
## [2.11.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.11.3...decap-cms-backend-gitlab@2.11.4) (2021-06-01)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.11.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.11.2...decap-cms-backend-gitlab@2.11.3) (2021-05-31)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.11.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.11.1...decap-cms-backend-gitlab@2.11.2) (2021-05-19)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.11.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.11.0...decap-cms-backend-gitlab@2.11.1) (2021-05-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** increase merge requests fetched to 100 ([#5320](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/5320)) ([0a1b00d](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/0a1b00d8b29a065b7d72fbb1744eb787da3b916e))
|
||||
|
||||
# [2.11.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.10.0...decap-cms-backend-gitlab@2.11.0) (2021-05-04)
|
||||
|
||||
### Features
|
||||
|
||||
- added react 17 as peer dependency in packages ([#5316](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/5316)) ([9e42380](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/9e423805707321396eec137f5b732a5b07a0dd3f))
|
||||
|
||||
# [2.10.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.9...decap-cms-backend-gitlab@2.10.0) (2021-04-14)
|
||||
|
||||
### Features
|
||||
|
||||
- Adds PKCE authentication for GitLab closes [#5236](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/5236) ([#5239](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/5239)) ([829409e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/829409e0bc03b4591ee6b59d9895adc4e7190037))
|
||||
|
||||
## [2.9.9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.8...decap-cms-backend-gitlab@2.9.9) (2021-02-23)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.9.8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.7...decap-cms-backend-gitlab@2.9.8) (2021-02-10)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.9.7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.6...decap-cms-backend-gitlab@2.9.7) (2021-02-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** increase rebase timeout ([#4905](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/4905)) ([d9d6860](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/d9d686025fe848fe460917cdef1934dea3295c9d))
|
||||
|
||||
## [2.9.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.5...decap-cms-backend-gitlab@2.9.6) (2021-01-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** skip creating a CI pipeline when rebasing merge request ([#4802](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/4802)) ([ce11dd2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/ce11dd23753fd7bb502c299058b83701f20058b2)), closes [#4786](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/4786)
|
||||
|
||||
## [2.9.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.4...decap-cms-backend-gitlab@2.9.5) (2020-09-20)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.9.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.9.3...decap-cms-backend-gitlab@2.9.4) (2020-09-15)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## 2.9.3 (2020-09-08)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "chore(release): publish" ([828bb16](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/828bb16415b8c22a34caa19c50c38b24ffe9ceae))
|
||||
|
||||
## 2.9.2 (2020-08-20)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "chore(release): publish" ([8262487](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/82624879ccbcb16610090041db28f00714d924c8))
|
||||
|
||||
## 2.9.1 (2020-07-27)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "chore(release): publish" ([118d50a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/118d50a7a70295f25073e564b5161aa2b9883056))
|
||||
|
||||
# [2.9.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.8.4...decap-cms-backend-gitlab@2.9.0) (2020-06-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- handle token expiry ([#3847](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3847)) ([285c940](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/285c940562548d7bc88de244123ba87ff66fba65))
|
||||
|
||||
### Features
|
||||
|
||||
- add backend status down indicator ([#3889](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3889)) ([a50edc7](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/a50edc70553ad6afa1acee6a51996ad226443f8c))
|
||||
- **backend-gitgateway:** improve deploy preview visibility ([#3882](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3882)) ([afc9bf4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/afc9bf4f3fe14ccb60851fc24e68922a6e4a85a9))
|
||||
|
||||
## [2.8.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.8.3...decap-cms-backend-gitlab@2.8.4) (2020-04-21)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.8.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.8.2...decap-cms-backend-gitlab@2.8.3) (2020-04-01)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.8.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.8.1...decap-cms-backend-gitlab@2.8.2) (2020-03-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- missing workflow timestamp ([#3445](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3445)) ([9616cdb](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/9616cdb8bb0a564771e5755bcd3718a07f2e2072))
|
||||
|
||||
## [2.8.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.8.0...decap-cms-backend-gitlab@2.8.1) (2020-03-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **locale:** Remove hard coded string literals ([#3333](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3333)) ([7c45a3c](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/7c45a3cda983be427864a56e58791565eb9232e2))
|
||||
|
||||
# [2.8.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.7.1...decap-cms-backend-gitlab@2.8.0) (2020-02-25)
|
||||
|
||||
### Features
|
||||
|
||||
- **core:** align GitHub metadata handling with other backends ([#3316](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3316)) ([7e0a8ad](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/7e0a8ad532012576dc5e40bd4e9d54522e307123)), closes [#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3292)
|
||||
|
||||
## [2.7.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.7.0...decap-cms-backend-gitlab@2.7.1) (2020-02-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "feat(core): Align GitHub metadata handling with other backends (#3292)" ([5bdd3df](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/5bdd3df9ccbb5149c22d79987ebdcd6cab4b261f)), closes [#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3292)
|
||||
|
||||
# [2.7.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.6.0...decap-cms-backend-gitlab@2.7.0) (2020-02-22)
|
||||
|
||||
### Features
|
||||
|
||||
- **core:** Align GitHub metadata handling with other backends ([#3292](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3292)) ([8193b5a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/8193b5ace89d6f14a6c756235a50b186a763b6b1))
|
||||
|
||||
# [2.6.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.5.3...decap-cms-backend-gitlab@2.6.0) (2020-02-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- filter paginated results ([#3216](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3216)) ([0a482b1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/0a482b10049bcfa022b81165cabf4512d77e0b88))
|
||||
- workflow file collection ([#3207](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3207)) ([d22f7e6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/d22f7e680e7064e8607cf8b420571fa40a6c314e))
|
||||
|
||||
### Features
|
||||
|
||||
- field based media/public folders ([#3208](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3208)) ([97bc0c8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/97bc0c8dc489e736f89d748ba832d78400fe4332))
|
||||
|
||||
### Reverts
|
||||
|
||||
- Revert "chore(release): publish" ([a015d1d](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/a015d1d92a4b1c0130c44fcef1c9ecdb157a0f07))
|
||||
|
||||
## [2.5.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.5.2...decap-cms-backend-gitlab@2.5.3) (2020-02-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **locale:** remove hard coded strings ([#3193](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3193)) ([fc91bf8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/fc91bf8781e65ce1dc946363dbb10419a145c66b))
|
||||
|
||||
## [2.5.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.5.1...decap-cms-backend-gitlab@2.5.2) (2020-01-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** check for shared group permissions ([#3122](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3122)) ([f1739e9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/f1739e978f9dee1de42dd5479ec80a5d991a9bfe))
|
||||
- **git-gateway-gitlab:** fix large media support for editorial workflow ([#3105](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/3105)) ([038803c](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/038803c9f249de386812652372c35c4c53935295))
|
||||
|
||||
## [2.5.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.5.0...decap-cms-backend-gitlab@2.5.1) (2020-01-14)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.5.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.5.0-beta.0...decap-cms-backend-gitlab@2.5.0) (2020-01-07)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.5.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.4.0...decap-cms-backend-gitlab@2.5.0-beta.0) (2019-12-18)
|
||||
|
||||
### Features
|
||||
|
||||
- bundle assets with content ([#2958](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2958)) ([2b41d8a](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/2b41d8a838a9c8a6b21cde2ddd16b9288334e298))
|
||||
|
||||
# [2.4.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.4.0-beta.1...decap-cms-backend-gitlab@2.4.0) (2019-12-18)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.4.0-beta.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.4.0-beta.0...decap-cms-backend-gitlab@2.4.0-beta.1) (2019-12-02)
|
||||
|
||||
### Features
|
||||
|
||||
- content in sub folders ([#2897](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2897)) ([afcfe5b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/afcfe5b6d5f32669e9061ec596bd35ad545d61a3))
|
||||
|
||||
# [2.4.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.3-beta.1...decap-cms-backend-gitlab@2.4.0-beta.0) (2019-11-07)
|
||||
|
||||
### Features
|
||||
|
||||
- add go back to site button ([#2538](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2538)) ([f206e7e](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/f206e7e5a13fb48ec6b27dce0dbb3a59b61de8f9))
|
||||
- enable specifying custom open authoring commit message ([#2810](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2810)) ([2841ff9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/2841ff9ffe58afcf4dba45514a84a262ad370f1d))
|
||||
|
||||
## [2.3.3-beta.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.3-beta.0...decap-cms-backend-gitlab@2.3.3-beta.1) (2019-09-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** exclude directories in paginated results ([#2668](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2668)) ([3903acb](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/3903acb))
|
||||
|
||||
## [2.3.3-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.2...decap-cms-backend-gitlab@2.3.3-beta.0) (2019-08-24)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.3.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.2-beta.0...decap-cms-backend-gitlab@2.3.2) (2019-04-10)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.3.2-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.1...decap-cms-backend-gitlab@2.3.2-beta.0) (2019-04-05)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.3.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.1-beta.1...decap-cms-backend-gitlab@2.3.1) (2019-03-29)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.3.1-beta.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.1-beta.0...decap-cms-backend-gitlab@2.3.1-beta.1) (2019-03-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- export on decap-cms and maps on esm ([#2244](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2244)) ([6ffd13b](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/6ffd13b))
|
||||
|
||||
## [2.3.1-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.3.0...decap-cms-backend-gitlab@2.3.1-beta.0) (2019-03-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- update peer dep versions ([#2234](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2234)) ([7987091](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/7987091))
|
||||
|
||||
# [2.3.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.2.0...decap-cms-backend-gitlab@2.3.0) (2019-03-22)
|
||||
|
||||
### Features
|
||||
|
||||
- add ES module builds ([#2215](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2215)) ([d142b32](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/d142b32))
|
||||
|
||||
# [2.2.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.2.0-beta.0...decap-cms-backend-gitlab@2.2.0) (2019-03-22)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
# [2.2.0-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.1.4-beta.0...decap-cms-backend-gitlab@2.2.0-beta.0) (2019-03-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix umd builds ([#2214](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2214)) ([e04f6be](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/e04f6be))
|
||||
|
||||
### Features
|
||||
|
||||
- provide usable UMD builds for all packages ([#2141](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2141)) ([82cc794](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/82cc794))
|
||||
|
||||
## [2.1.4-beta.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.1.3...decap-cms-backend-gitlab@2.1.4-beta.0) (2019-03-15)
|
||||
|
||||
### Features
|
||||
|
||||
- upgrade to Emotion 10 ([#2166](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/2166)) ([ccef446](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/ccef446))
|
||||
|
||||
## [2.1.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.1.2...decap-cms-backend-gitlab@2.1.3) (2019-03-08)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.1.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.1.1...decap-cms-backend-gitlab@2.1.2) (2019-02-26)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
## [2.1.1](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.1.0...decap-cms-backend-gitlab@2.1.1) (2018-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** show svg previews ([#1946](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1946)) ([c3adebe](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/c3adebe))
|
||||
|
||||
# [2.1.0](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.6...decap-cms-backend-gitlab@2.1.0) (2018-11-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backend-gitlab:** support folder names with whitespace ([#1799](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1799)) ([a9f69f9](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/a9f69f9))
|
||||
|
||||
### Features
|
||||
|
||||
- allow custom logo on auth page ([#1818](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1818)) ([c6ae1e8](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/c6ae1e8))
|
||||
|
||||
<a name="2.0.6"></a>
|
||||
|
||||
## [2.0.6](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.5...decap-cms-backend-gitlab@2.0.6) (2018-08-27)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
<a name="2.0.5"></a>
|
||||
|
||||
## [2.0.5](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.4...decap-cms-backend-gitlab@2.0.5) (2018-08-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **gitlab:** fetch media library images through API ([#1433](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1433)) ([83d2adc](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/83d2adc))
|
||||
|
||||
<a name="2.0.4"></a>
|
||||
|
||||
## [2.0.4](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.3...decap-cms-backend-gitlab@2.0.4) (2018-08-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **backends:** fix commit message handling ([#1568](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1568)) ([f7e7120](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/f7e7120))
|
||||
|
||||
<a name="2.0.3"></a>
|
||||
|
||||
## [2.0.3](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.2...decap-cms-backend-gitlab@2.0.3) (2018-08-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **gitlab:** fix uploads ([#1566](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/issues/1566)) ([d59c990](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/commit/d59c990))
|
||||
|
||||
<a name="2.0.2"></a>
|
||||
|
||||
## [2.0.2](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab/compare/decap-cms-backend-gitlab@2.0.1...decap-cms-backend-gitlab@2.0.2) (2018-07-28)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
|
||||
<a name="2.0.1"></a>
|
||||
|
||||
## 2.0.1 (2018-07-26)
|
||||
|
||||
<a name="2.0.0"></a>
|
||||
|
||||
# 2.0.0 (2018-07-26)
|
||||
|
||||
**Note:** Version bump only for package decap-cms-backend-gitlab
|
||||
22
node_modules/decap-cms-backend-gitlab/LICENSE
generated
vendored
Normal file
22
node_modules/decap-cms-backend-gitlab/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2016 Netlify <decap@p-m.si>
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
13
node_modules/decap-cms-backend-gitlab/README.md
generated
vendored
Normal file
13
node_modules/decap-cms-backend-gitlab/README.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# GitLab backend
|
||||
|
||||
An abstraction layer between the CMS and [GitLab](https://docs.gitlab.com/ee/api/README.html)
|
||||
|
||||
## Code structure
|
||||
|
||||
`Implementation` for [File Management System API](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-util/README.md) based on `Api`. With [Editorial Workflow](https://www.decapcms.org/docs/beta-features/#gitlab-and-bitbucket-editorial-workflow-support) uses merge requests labels to track unpublished entries statuses.
|
||||
|
||||
`Api` - A wrapper for GitLab REST API.
|
||||
|
||||
`AuthenticationPage` - A component uses [lib-auth](https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-lib-auth/README.md) to facilitate OAuth, PKCE and implicit authentication.
|
||||
|
||||
Look at tests or types for more info.
|
||||
64
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js
generated
vendored
Normal file
64
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
23
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js.LICENSE.txt
generated
vendored
Normal file
23
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js.LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <https://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
1
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js.map
generated
vendored
Normal file
1
node_modules/decap-cms-backend-gitlab/dist/decap-cms-backend-gitlab.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
818
node_modules/decap-cms-backend-gitlab/dist/esm/API.js
generated
vendored
Normal file
818
node_modules/decap-cms-backend-gitlab/dist/esm/API.js
generated
vendored
Normal file
@@ -0,0 +1,818 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = exports.API_NAME = void 0;
|
||||
exports.getMaxAccess = getMaxAccess;
|
||||
var _trimStart2 = _interopRequireDefault(require("lodash/trimStart"));
|
||||
var _result2 = _interopRequireDefault(require("lodash/result"));
|
||||
var _partial2 = _interopRequireDefault(require("lodash/partial"));
|
||||
var _flow2 = _interopRequireDefault(require("lodash/flow"));
|
||||
var _apolloClient = require("apollo-client");
|
||||
var _apolloCacheInmemory = require("apollo-cache-inmemory");
|
||||
var _apolloLinkHttp = require("apollo-link-http");
|
||||
var _apolloLinkContext = require("apollo-link-context");
|
||||
var _decapCmsLibUtil = require("decap-cms-lib-util");
|
||||
var _jsBase = require("js-base64");
|
||||
var _immutable = require("immutable");
|
||||
var _path = require("path");
|
||||
var queries = _interopRequireWildcard(require("./queries"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
||||
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
||||
const NO_CACHE = 'no-cache';
|
||||
const API_NAME = exports.API_NAME = 'GitLab';
|
||||
var CommitAction = /*#__PURE__*/function (CommitAction) {
|
||||
CommitAction["CREATE"] = "create";
|
||||
CommitAction["DELETE"] = "delete";
|
||||
CommitAction["MOVE"] = "move";
|
||||
CommitAction["UPDATE"] = "update";
|
||||
return CommitAction;
|
||||
}(CommitAction || {});
|
||||
var GitLabCommitStatuses = /*#__PURE__*/function (GitLabCommitStatuses) {
|
||||
GitLabCommitStatuses["Pending"] = "pending";
|
||||
GitLabCommitStatuses["Running"] = "running";
|
||||
GitLabCommitStatuses["Success"] = "success";
|
||||
GitLabCommitStatuses["Failed"] = "failed";
|
||||
GitLabCommitStatuses["Canceled"] = "canceled";
|
||||
return GitLabCommitStatuses;
|
||||
}(GitLabCommitStatuses || {});
|
||||
function getMaxAccess(groups) {
|
||||
return groups.reduce((previous, current) => {
|
||||
if (current.group_access_level > previous.group_access_level) {
|
||||
return current;
|
||||
}
|
||||
return previous;
|
||||
}, groups[0]);
|
||||
}
|
||||
function batch(items, maxPerBatch, action) {
|
||||
for (let index = 0; index < items.length; index = index + maxPerBatch) {
|
||||
const itemsSlice = items.slice(index, index + maxPerBatch);
|
||||
action(itemsSlice);
|
||||
}
|
||||
}
|
||||
class API {
|
||||
constructor(config) {
|
||||
_defineProperty(this, "apiRoot", void 0);
|
||||
_defineProperty(this, "graphQLAPIRoot", void 0);
|
||||
_defineProperty(this, "token", void 0);
|
||||
_defineProperty(this, "branch", void 0);
|
||||
_defineProperty(this, "useOpenAuthoring", void 0);
|
||||
_defineProperty(this, "repo", void 0);
|
||||
_defineProperty(this, "repoURL", void 0);
|
||||
_defineProperty(this, "commitAuthor", void 0);
|
||||
_defineProperty(this, "squashMerges", void 0);
|
||||
_defineProperty(this, "initialWorkflowStatus", void 0);
|
||||
_defineProperty(this, "cmsLabelPrefix", void 0);
|
||||
_defineProperty(this, "graphQLClient", void 0);
|
||||
_defineProperty(this, "withAuthorizationHeaders", req => {
|
||||
const withHeaders = _decapCmsLibUtil.unsentRequest.withHeaders(this.token ? {
|
||||
Authorization: `Bearer ${this.token}`
|
||||
} : {}, req);
|
||||
return Promise.resolve(withHeaders);
|
||||
});
|
||||
_defineProperty(this, "buildRequest", async req => {
|
||||
const withRoot = _decapCmsLibUtil.unsentRequest.withRoot(this.apiRoot)(req);
|
||||
const withAuthorizationHeaders = await this.withAuthorizationHeaders(withRoot);
|
||||
if (withAuthorizationHeaders.has('cache')) {
|
||||
return withAuthorizationHeaders;
|
||||
} else {
|
||||
const withNoCache = _decapCmsLibUtil.unsentRequest.withNoCache(withAuthorizationHeaders);
|
||||
return withNoCache;
|
||||
}
|
||||
});
|
||||
_defineProperty(this, "request", async req => {
|
||||
try {
|
||||
return (0, _decapCmsLibUtil.requestWithBackoff)(this, req);
|
||||
} catch (err) {
|
||||
throw new _decapCmsLibUtil.APIError(err.message, null, API_NAME);
|
||||
}
|
||||
});
|
||||
_defineProperty(this, "responseToJSON", (0, _decapCmsLibUtil.responseParser)({
|
||||
format: 'json',
|
||||
apiName: API_NAME
|
||||
}));
|
||||
_defineProperty(this, "responseToBlob", (0, _decapCmsLibUtil.responseParser)({
|
||||
format: 'blob',
|
||||
apiName: API_NAME
|
||||
}));
|
||||
_defineProperty(this, "responseToText", (0, _decapCmsLibUtil.responseParser)({
|
||||
format: 'text',
|
||||
apiName: API_NAME
|
||||
}));
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
_defineProperty(this, "requestJSON", req => this.request(req).then(this.responseToJSON));
|
||||
_defineProperty(this, "requestText", req => this.request(req).then(this.responseToText));
|
||||
_defineProperty(this, "user", () => this.requestJSON('/user'));
|
||||
_defineProperty(this, "WRITE_ACCESS", 30);
|
||||
_defineProperty(this, "MAINTAINER_ACCESS", 40);
|
||||
_defineProperty(this, "hasWriteAccess", async () => {
|
||||
const {
|
||||
shared_with_groups: sharedWithGroups,
|
||||
permissions
|
||||
} = await this.requestJSON(this.repoURL);
|
||||
const {
|
||||
project_access: projectAccess,
|
||||
group_access: groupAccess
|
||||
} = permissions;
|
||||
if (projectAccess && projectAccess.access_level >= this.WRITE_ACCESS) {
|
||||
return true;
|
||||
}
|
||||
if (groupAccess && groupAccess.access_level >= this.WRITE_ACCESS) {
|
||||
return true;
|
||||
}
|
||||
// check for group write permissions
|
||||
if (sharedWithGroups && sharedWithGroups.length > 0) {
|
||||
const maxAccess = getMaxAccess(sharedWithGroups);
|
||||
// maintainer access
|
||||
if (maxAccess.group_access_level >= this.MAINTAINER_ACCESS) {
|
||||
return true;
|
||||
}
|
||||
// developer access
|
||||
if (maxAccess.group_access_level >= this.WRITE_ACCESS) {
|
||||
// check permissions to merge and push
|
||||
try {
|
||||
const branch = await this.getDefaultBranch();
|
||||
if (branch.developers_can_merge && branch.developers_can_push) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Failed getting default branch', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
_defineProperty(this, "readFile", async (path, sha, {
|
||||
parseText = true,
|
||||
branch = this.branch
|
||||
} = {}) => {
|
||||
const fetchContent = async () => {
|
||||
const content = await this.request({
|
||||
url: `${this.repoURL}/repository/files/${encodeURIComponent(path)}/raw`,
|
||||
params: {
|
||||
ref: branch
|
||||
},
|
||||
cache: 'no-store'
|
||||
}).then(parseText ? this.responseToText : this.responseToBlob);
|
||||
return content;
|
||||
};
|
||||
const content = await (0, _decapCmsLibUtil.readFile)(sha, fetchContent, _decapCmsLibUtil.localForage, parseText);
|
||||
return content;
|
||||
});
|
||||
_defineProperty(this, "getCursorFromHeaders", headers => {
|
||||
const page = parseInt(headers.get('X-Page'), 10);
|
||||
const pageCount = parseInt(headers.get('X-Total-Pages'), 10);
|
||||
const pageSize = parseInt(headers.get('X-Per-Page'), 10);
|
||||
const count = parseInt(headers.get('X-Total'), 10);
|
||||
const links = (0, _decapCmsLibUtil.parseLinkHeader)(headers.get('Link'));
|
||||
const actions = (0, _immutable.Map)(links).keySeq().flatMap(key => key === 'prev' && page > 1 || key === 'next' && page < pageCount || key === 'first' && page > 1 || key === 'last' && page < pageCount ? [key] : []);
|
||||
return _decapCmsLibUtil.Cursor.create({
|
||||
actions,
|
||||
meta: {
|
||||
page,
|
||||
count,
|
||||
pageSize,
|
||||
pageCount
|
||||
},
|
||||
data: {
|
||||
links
|
||||
}
|
||||
});
|
||||
});
|
||||
_defineProperty(this, "getCursor", ({
|
||||
headers
|
||||
}) => this.getCursorFromHeaders(headers));
|
||||
// Gets a cursor without retrieving the entries by using a HEAD
|
||||
// request
|
||||
_defineProperty(this, "fetchCursor", req => (0, _flow2.default)([_decapCmsLibUtil.unsentRequest.withMethod('HEAD'), this.request, (0, _decapCmsLibUtil.then)(this.getCursor)])(req));
|
||||
_defineProperty(this, "fetchCursorAndEntries", req => (0, _flow2.default)([_decapCmsLibUtil.unsentRequest.withMethod('GET'), this.request, p => Promise.all([p.then(this.getCursor), p.then(this.responseToJSON).catch(e => {
|
||||
if (e.status === 404) {
|
||||
return [];
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
})]), (0, _decapCmsLibUtil.then)(([cursor, entries]) => ({
|
||||
cursor,
|
||||
entries
|
||||
}))])(req));
|
||||
_defineProperty(this, "listFiles", async (path, recursive = false) => {
|
||||
const {
|
||||
entries,
|
||||
cursor
|
||||
} = await this.fetchCursorAndEntries({
|
||||
url: `${this.repoURL}/repository/tree`,
|
||||
params: {
|
||||
path,
|
||||
ref: this.branch,
|
||||
recursive
|
||||
}
|
||||
});
|
||||
return {
|
||||
files: entries.filter(({
|
||||
type
|
||||
}) => type === 'blob'),
|
||||
cursor
|
||||
};
|
||||
});
|
||||
_defineProperty(this, "traverseCursor", async (cursor, action) => {
|
||||
const link = cursor.data.getIn(['links', action]);
|
||||
const {
|
||||
entries,
|
||||
cursor: newCursor
|
||||
} = await this.fetchCursorAndEntries(link);
|
||||
return {
|
||||
entries: entries.filter(({
|
||||
type
|
||||
}) => type === 'blob'),
|
||||
cursor: newCursor
|
||||
};
|
||||
});
|
||||
_defineProperty(this, "listAllFilesGraphQL", async (path, recursive, branch) => {
|
||||
const files = [];
|
||||
let blobsPaths;
|
||||
let cursor;
|
||||
do {
|
||||
blobsPaths = await this.graphQLClient.query({
|
||||
query: queries.files,
|
||||
variables: {
|
||||
repo: this.repo,
|
||||
branch,
|
||||
path,
|
||||
recursive,
|
||||
cursor
|
||||
}
|
||||
});
|
||||
files.push(...blobsPaths.data.project.repository.tree.blobs.nodes);
|
||||
cursor = blobsPaths.data.project.repository.tree.blobs.pageInfo.endCursor;
|
||||
} while (blobsPaths.data.project.repository.tree.blobs.pageInfo.hasNextPage);
|
||||
return files;
|
||||
});
|
||||
_defineProperty(this, "readFilesGraphQL", async files => {
|
||||
const paths = files.map(({
|
||||
path
|
||||
}) => path);
|
||||
const blobPromises = [];
|
||||
batch(paths, 90, slice => {
|
||||
blobPromises.push(this.graphQLClient.query({
|
||||
query: queries.blobs,
|
||||
variables: {
|
||||
repo: this.repo,
|
||||
branch: this.branch,
|
||||
paths: slice
|
||||
},
|
||||
fetchPolicy: 'cache-first'
|
||||
}));
|
||||
});
|
||||
const commitPromises = [];
|
||||
batch(paths, 8, slice => {
|
||||
commitPromises.push(this.graphQLClient.query({
|
||||
query: queries.lastCommits(slice),
|
||||
variables: {
|
||||
repo: this.repo,
|
||||
branch: this.branch
|
||||
},
|
||||
fetchPolicy: 'cache-first'
|
||||
}));
|
||||
});
|
||||
const [blobsResults, commitsResults] = await Promise.all([(await Promise.all(blobPromises)).map(result => result.data.project.repository.blobs.nodes), (await Promise.all(commitPromises)).map(result => Object.values(result.data.project.repository).map(({
|
||||
lastCommit
|
||||
}) => lastCommit).filter(Boolean))]);
|
||||
const blobs = blobsResults.flat().map(result => result.data);
|
||||
const metadata = commitsResults.flat().map(({
|
||||
author,
|
||||
authoredDate,
|
||||
authorName
|
||||
}) => ({
|
||||
author: author ? author.name || author.username || author.publicEmail : authorName,
|
||||
updatedOn: authoredDate
|
||||
}));
|
||||
const filesWithData = files.map((file, index) => ({
|
||||
file: _objectSpread(_objectSpread({}, file), metadata[index]),
|
||||
data: blobs[index]
|
||||
}));
|
||||
return filesWithData;
|
||||
});
|
||||
_defineProperty(this, "listAllFiles", async (path, recursive = false, branch = this.branch) => {
|
||||
if (this.graphQLClient) {
|
||||
return await this.listAllFilesGraphQL(path, recursive, branch);
|
||||
}
|
||||
const entries = [];
|
||||
// eslint-disable-next-line prefer-const
|
||||
let {
|
||||
cursor,
|
||||
entries: initialEntries
|
||||
} = await this.fetchCursorAndEntries({
|
||||
url: `${this.repoURL}/repository/tree`,
|
||||
// Get the maximum number of entries per page
|
||||
params: {
|
||||
path,
|
||||
ref: branch,
|
||||
per_page: 100,
|
||||
recursive
|
||||
}
|
||||
});
|
||||
entries.push(...initialEntries);
|
||||
while (cursor && cursor.actions.has('next')) {
|
||||
const link = cursor.data.getIn(['links', 'next']);
|
||||
const {
|
||||
cursor: newCursor,
|
||||
entries: newEntries
|
||||
} = await this.fetchCursorAndEntries(link);
|
||||
entries.push(...newEntries);
|
||||
cursor = newCursor;
|
||||
}
|
||||
return entries.filter(({
|
||||
type
|
||||
}) => type === 'blob');
|
||||
});
|
||||
_defineProperty(this, "toBase64", str => Promise.resolve(_jsBase.Base64.encode(str)));
|
||||
_defineProperty(this, "fromBase64", str => _jsBase.Base64.decode(str));
|
||||
_defineProperty(this, "deleteFiles", (paths, commitMessage) => {
|
||||
const branch = this.branch;
|
||||
const commitParams = {
|
||||
commit_message: commitMessage,
|
||||
branch
|
||||
};
|
||||
if (this.commitAuthor) {
|
||||
const {
|
||||
name,
|
||||
email
|
||||
} = this.commitAuthor;
|
||||
commitParams.author_name = name;
|
||||
commitParams.author_email = email;
|
||||
}
|
||||
const items = paths.map(path => ({
|
||||
path,
|
||||
action: CommitAction.DELETE
|
||||
}));
|
||||
return this.uploadAndCommit(items, {
|
||||
commitMessage
|
||||
});
|
||||
});
|
||||
this.apiRoot = config.apiRoot || 'https://gitlab.com/api/v4';
|
||||
this.graphQLAPIRoot = config.graphQLAPIRoot || 'https://gitlab.com/api/graphql';
|
||||
this.token = config.token || false;
|
||||
this.branch = config.branch || 'master';
|
||||
this.repo = config.repo || '';
|
||||
this.repoURL = `/projects/${encodeURIComponent(this.repo)}`;
|
||||
this.squashMerges = config.squashMerges;
|
||||
this.initialWorkflowStatus = config.initialWorkflowStatus;
|
||||
this.cmsLabelPrefix = config.cmsLabelPrefix;
|
||||
if (config.useGraphQL === true) {
|
||||
this.graphQLClient = this.getApolloClient();
|
||||
}
|
||||
}
|
||||
getApolloClient() {
|
||||
const authLink = (0, _apolloLinkContext.setContext)((_, {
|
||||
headers
|
||||
}) => {
|
||||
return {
|
||||
headers: _objectSpread(_objectSpread({
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}, headers), {}, {
|
||||
authorization: this.token ? `token ${this.token}` : ''
|
||||
})
|
||||
};
|
||||
});
|
||||
const httpLink = (0, _apolloLinkHttp.createHttpLink)({
|
||||
uri: this.graphQLAPIRoot
|
||||
});
|
||||
return new _apolloClient.ApolloClient({
|
||||
link: authLink.concat(httpLink),
|
||||
cache: new _apolloCacheInmemory.InMemoryCache(),
|
||||
defaultOptions: {
|
||||
watchQuery: {
|
||||
fetchPolicy: NO_CACHE,
|
||||
errorPolicy: 'ignore'
|
||||
},
|
||||
query: {
|
||||
fetchPolicy: NO_CACHE,
|
||||
errorPolicy: 'all'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
reset() {
|
||||
var _this$graphQLClient;
|
||||
return (_this$graphQLClient = this.graphQLClient) === null || _this$graphQLClient === void 0 ? void 0 : _this$graphQLClient.resetStore();
|
||||
}
|
||||
async readFileMetadata(path, sha) {
|
||||
const fetchFileMetadata = async () => {
|
||||
try {
|
||||
const result = await this.requestJSON({
|
||||
url: `${this.repoURL}/repository/commits`,
|
||||
params: {
|
||||
path,
|
||||
ref_name: this.branch
|
||||
}
|
||||
});
|
||||
const commit = result[0];
|
||||
return {
|
||||
author: commit.author_name || commit.author_email,
|
||||
updatedOn: commit.authored_date
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
author: '',
|
||||
updatedOn: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
const fileMetadata = await (0, _decapCmsLibUtil.readFileMetadata)(sha, fetchFileMetadata, _decapCmsLibUtil.localForage);
|
||||
return fileMetadata;
|
||||
}
|
||||
async getBranch(branchName) {
|
||||
const branch = await this.requestJSON(`${this.repoURL}/repository/branches/${encodeURIComponent(branchName)}`);
|
||||
return branch;
|
||||
}
|
||||
async uploadAndCommit(items, {
|
||||
commitMessage = '',
|
||||
branch = this.branch,
|
||||
newBranch = false
|
||||
}) {
|
||||
const actions = items.map(item => _objectSpread(_objectSpread({
|
||||
action: item.action,
|
||||
file_path: item.path
|
||||
}, item.oldPath ? {
|
||||
previous_path: item.oldPath
|
||||
} : {}), item.base64Content !== undefined ? {
|
||||
content: item.base64Content,
|
||||
encoding: 'base64'
|
||||
} : {}));
|
||||
const commitParams = _objectSpread({
|
||||
branch,
|
||||
commit_message: commitMessage,
|
||||
actions
|
||||
}, newBranch ? {
|
||||
start_branch: this.branch
|
||||
} : {});
|
||||
if (this.commitAuthor) {
|
||||
const {
|
||||
name,
|
||||
email
|
||||
} = this.commitAuthor;
|
||||
commitParams.author_name = name;
|
||||
commitParams.author_email = email;
|
||||
}
|
||||
try {
|
||||
const result = await this.requestJSON({
|
||||
url: `${this.repoURL}/repository/commits`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(commitParams)
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
const message = error.message || '';
|
||||
if (newBranch && message.includes(`Could not update ${branch}`)) {
|
||||
await (0, _decapCmsLibUtil.throwOnConflictingBranches)(branch, name => this.getBranch(name), API_NAME);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async getCommitItems(files, branch) {
|
||||
const items = await Promise.all(files.map(async file => {
|
||||
const [base64Content, fileExists] = await Promise.all([(0, _result2.default)(file, 'toBase64', (0, _partial2.default)(this.toBase64, file.raw)), this.isFileExists(file.path, branch)]);
|
||||
let action = CommitAction.CREATE;
|
||||
let path = (0, _trimStart2.default)(file.path, '/');
|
||||
let oldPath = undefined;
|
||||
if (fileExists) {
|
||||
oldPath = file.newPath && path;
|
||||
action = file.newPath && file.newPath !== oldPath ? CommitAction.MOVE : CommitAction.UPDATE;
|
||||
path = file.newPath ? (0, _trimStart2.default)(file.newPath, '/') : path;
|
||||
}
|
||||
return {
|
||||
action,
|
||||
base64Content,
|
||||
path,
|
||||
oldPath
|
||||
};
|
||||
}));
|
||||
|
||||
// move children
|
||||
for (const item of items.filter(i => i.oldPath && i.action === CommitAction.MOVE)) {
|
||||
const sourceDir = (0, _path.dirname)(item.oldPath);
|
||||
const destDir = (0, _path.dirname)(item.path);
|
||||
const children = await this.listAllFiles(sourceDir, true, branch);
|
||||
children.filter(f => f.path !== item.oldPath).forEach(file => {
|
||||
items.push({
|
||||
action: CommitAction.MOVE,
|
||||
path: file.path.replace(sourceDir, destDir),
|
||||
oldPath: file.path
|
||||
});
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
async persistFiles(dataFiles, mediaFiles, options) {
|
||||
const files = [...dataFiles, ...mediaFiles];
|
||||
if (options.useWorkflow) {
|
||||
const slug = dataFiles[0].slug;
|
||||
return this.editorialWorkflowGit(files, slug, options);
|
||||
} else {
|
||||
const items = await this.getCommitItems(files, this.branch);
|
||||
return this.uploadAndCommit(items, {
|
||||
commitMessage: options.commitMessage
|
||||
});
|
||||
}
|
||||
}
|
||||
async getMergeRequests(sourceBranch) {
|
||||
const mergeRequests = await this.requestJSON({
|
||||
url: `${this.repoURL}/merge_requests`,
|
||||
params: _objectSpread({
|
||||
state: 'opened',
|
||||
labels: 'Any',
|
||||
per_page: 100,
|
||||
target_branch: this.branch
|
||||
}, sourceBranch ? {
|
||||
source_branch: sourceBranch
|
||||
} : {})
|
||||
});
|
||||
return mergeRequests.filter(mr => mr.source_branch.startsWith(_decapCmsLibUtil.CMS_BRANCH_PREFIX) && mr.labels.some(l => (0, _decapCmsLibUtil.isCMSLabel)(l, this.cmsLabelPrefix)));
|
||||
}
|
||||
async listUnpublishedBranches() {
|
||||
console.log('%c Checking for Unpublished entries', 'line-height: 30px;text-align: center;font-weight: bold');
|
||||
const mergeRequests = await this.getMergeRequests();
|
||||
const branches = mergeRequests.map(mr => mr.source_branch);
|
||||
return branches;
|
||||
}
|
||||
async getFileId(path, branch) {
|
||||
const request = await this.request({
|
||||
method: 'HEAD',
|
||||
url: `${this.repoURL}/repository/files/${encodeURIComponent(path)}`,
|
||||
params: {
|
||||
ref: branch
|
||||
}
|
||||
});
|
||||
const blobId = request.headers.get('X-Gitlab-Blob-Id');
|
||||
return blobId;
|
||||
}
|
||||
async isFileExists(path, branch) {
|
||||
const fileExists = await this.requestText({
|
||||
method: 'HEAD',
|
||||
url: `${this.repoURL}/repository/files/${encodeURIComponent(path)}`,
|
||||
params: {
|
||||
ref: branch
|
||||
}
|
||||
}).then(() => true).catch(error => {
|
||||
if (error instanceof _decapCmsLibUtil.APIError && error.status === 404) {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
return fileExists;
|
||||
}
|
||||
async getBranchMergeRequest(branch) {
|
||||
const mergeRequests = await this.getMergeRequests(branch);
|
||||
if (mergeRequests.length <= 0) {
|
||||
throw new _decapCmsLibUtil.EditorialWorkflowError('content is not under editorial workflow', true);
|
||||
}
|
||||
return mergeRequests[0];
|
||||
}
|
||||
async getDifferences(to, from = this.branch) {
|
||||
if (to === from) {
|
||||
return [];
|
||||
}
|
||||
const result = await this.requestJSON({
|
||||
url: `${this.repoURL}/repository/compare`,
|
||||
params: {
|
||||
from,
|
||||
to
|
||||
}
|
||||
});
|
||||
if (result.diffs.length >= 1000) {
|
||||
throw new _decapCmsLibUtil.APIError('Diff limit reached', null, API_NAME);
|
||||
}
|
||||
return result.diffs.map(d => {
|
||||
let status = 'modified';
|
||||
if (d.new_file) {
|
||||
status = 'added';
|
||||
} else if (d.deleted_file) {
|
||||
status = 'deleted';
|
||||
} else if (d.renamed_file) {
|
||||
status = 'renamed';
|
||||
}
|
||||
return {
|
||||
status,
|
||||
oldPath: d.old_path,
|
||||
newPath: d.new_path,
|
||||
newFile: d.new_file,
|
||||
path: d.new_path || d.old_path,
|
||||
binary: d.diff.startsWith('Binary') || /.svg$/.test(d.new_path)
|
||||
};
|
||||
});
|
||||
}
|
||||
async retrieveUnpublishedEntryData(contentKey) {
|
||||
const {
|
||||
collection,
|
||||
slug
|
||||
} = (0, _decapCmsLibUtil.parseContentKey)(contentKey);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
const diffs = await this.getDifferences(mergeRequest.sha);
|
||||
const diffsWithIds = await Promise.all(diffs.map(async d => {
|
||||
const {
|
||||
path,
|
||||
newFile
|
||||
} = d;
|
||||
const id = await this.getFileId(path, branch);
|
||||
return {
|
||||
id,
|
||||
path,
|
||||
newFile
|
||||
};
|
||||
}));
|
||||
const label = mergeRequest.labels.find(l => (0, _decapCmsLibUtil.isCMSLabel)(l, this.cmsLabelPrefix));
|
||||
const status = (0, _decapCmsLibUtil.labelToStatus)(label, this.cmsLabelPrefix);
|
||||
const updatedAt = mergeRequest.updated_at;
|
||||
const pullRequestAuthor = mergeRequest.author.name;
|
||||
return {
|
||||
collection,
|
||||
slug,
|
||||
status,
|
||||
diffs: diffsWithIds,
|
||||
updatedAt,
|
||||
pullRequestAuthor
|
||||
};
|
||||
}
|
||||
async rebaseMergeRequest(mergeRequest) {
|
||||
let rebase = await this.requestJSON({
|
||||
method: 'PUT',
|
||||
url: `${this.repoURL}/merge_requests/${mergeRequest.iid}/rebase?skip_ci=true`
|
||||
});
|
||||
let i = 1;
|
||||
while (rebase.rebase_in_progress) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
rebase = await this.requestJSON({
|
||||
url: `${this.repoURL}/merge_requests/${mergeRequest.iid}`,
|
||||
params: {
|
||||
include_rebase_in_progress: true
|
||||
}
|
||||
});
|
||||
if (!rebase.rebase_in_progress || i > 30) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (rebase.rebase_in_progress) {
|
||||
throw new _decapCmsLibUtil.APIError('Timed out rebasing merge request', null, API_NAME);
|
||||
} else if (rebase.merge_error) {
|
||||
throw new _decapCmsLibUtil.APIError(`Rebase error: ${rebase.merge_error}`, null, API_NAME);
|
||||
}
|
||||
}
|
||||
async createMergeRequest(branch, commitMessage, status) {
|
||||
await this.requestJSON({
|
||||
method: 'POST',
|
||||
url: `${this.repoURL}/merge_requests`,
|
||||
params: {
|
||||
source_branch: branch,
|
||||
target_branch: this.branch,
|
||||
title: commitMessage,
|
||||
description: _decapCmsLibUtil.DEFAULT_PR_BODY,
|
||||
labels: (0, _decapCmsLibUtil.statusToLabel)(status, this.cmsLabelPrefix),
|
||||
remove_source_branch: true,
|
||||
squash: this.squashMerges
|
||||
}
|
||||
});
|
||||
}
|
||||
async editorialWorkflowGit(files, slug, options) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(options.collectionName, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const unpublished = options.unpublished || false;
|
||||
if (!unpublished) {
|
||||
const items = await this.getCommitItems(files, this.branch);
|
||||
await this.uploadAndCommit(items, {
|
||||
commitMessage: options.commitMessage,
|
||||
branch,
|
||||
newBranch: true
|
||||
});
|
||||
await this.createMergeRequest(branch, options.commitMessage, options.status || this.initialWorkflowStatus);
|
||||
} else {
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
await this.rebaseMergeRequest(mergeRequest);
|
||||
const [items, diffs] = await Promise.all([this.getCommitItems(files, branch), this.getDifferences(branch)]);
|
||||
// mark files for deletion
|
||||
for (const diff of diffs.filter(d => d.binary)) {
|
||||
if (!items.some(item => item.path === diff.path)) {
|
||||
items.push({
|
||||
action: CommitAction.DELETE,
|
||||
path: diff.newPath
|
||||
});
|
||||
}
|
||||
}
|
||||
await this.uploadAndCommit(items, {
|
||||
commitMessage: options.commitMessage,
|
||||
branch
|
||||
});
|
||||
}
|
||||
}
|
||||
async updateMergeRequestLabels(mergeRequest, labels) {
|
||||
await this.requestJSON({
|
||||
method: 'PUT',
|
||||
url: `${this.repoURL}/merge_requests/${mergeRequest.iid}`,
|
||||
params: {
|
||||
labels: labels.join(',')
|
||||
}
|
||||
});
|
||||
}
|
||||
async updateUnpublishedEntryStatus(collection, slug, newStatus) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collection, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
const labels = [...mergeRequest.labels.filter(label => !(0, _decapCmsLibUtil.isCMSLabel)(label, this.cmsLabelPrefix)), (0, _decapCmsLibUtil.statusToLabel)(newStatus, this.cmsLabelPrefix)];
|
||||
await this.updateMergeRequestLabels(mergeRequest, labels);
|
||||
}
|
||||
async mergeMergeRequest(mergeRequest) {
|
||||
await this.requestJSON({
|
||||
method: 'PUT',
|
||||
url: `${this.repoURL}/merge_requests/${mergeRequest.iid}/merge`,
|
||||
params: {
|
||||
merge_commit_message: _decapCmsLibUtil.MERGE_COMMIT_MESSAGE,
|
||||
squash_commit_message: _decapCmsLibUtil.MERGE_COMMIT_MESSAGE,
|
||||
squash: this.squashMerges,
|
||||
should_remove_source_branch: true
|
||||
}
|
||||
});
|
||||
}
|
||||
async publishUnpublishedEntry(collectionName, slug) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collectionName, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
await this.mergeMergeRequest(mergeRequest);
|
||||
}
|
||||
async closeMergeRequest(mergeRequest) {
|
||||
await this.requestJSON({
|
||||
method: 'PUT',
|
||||
url: `${this.repoURL}/merge_requests/${mergeRequest.iid}`,
|
||||
params: {
|
||||
state_event: 'close'
|
||||
}
|
||||
});
|
||||
}
|
||||
async getDefaultBranch() {
|
||||
const branch = await this.getBranch(this.branch);
|
||||
return branch;
|
||||
}
|
||||
async isShaExistsInBranch(branch, sha) {
|
||||
const refs = await this.requestJSON({
|
||||
url: `${this.repoURL}/repository/commits/${sha}/refs`,
|
||||
params: {
|
||||
type: 'branch'
|
||||
}
|
||||
});
|
||||
return refs.some(r => r.name === branch);
|
||||
}
|
||||
async deleteBranch(branch) {
|
||||
await this.request({
|
||||
method: 'DELETE',
|
||||
url: `${this.repoURL}/repository/branches/${encodeURIComponent(branch)}`
|
||||
});
|
||||
}
|
||||
async deleteUnpublishedEntry(collectionName, slug) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collectionName, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
await this.closeMergeRequest(mergeRequest);
|
||||
await this.deleteBranch(branch);
|
||||
}
|
||||
async getMergeRequestStatues(mergeRequest, branch) {
|
||||
const statuses = await this.requestJSON({
|
||||
url: `${this.repoURL}/repository/commits/${mergeRequest.sha}/statuses`,
|
||||
params: {
|
||||
ref: branch
|
||||
}
|
||||
});
|
||||
return statuses;
|
||||
}
|
||||
async getStatuses(collectionName, slug) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collectionName, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
const statuses = await this.getMergeRequestStatues(mergeRequest, branch);
|
||||
return statuses.map(({
|
||||
name,
|
||||
status,
|
||||
target_url
|
||||
}) => ({
|
||||
context: name,
|
||||
state: status === GitLabCommitStatuses.Success ? _decapCmsLibUtil.PreviewState.Success : _decapCmsLibUtil.PreviewState.Other,
|
||||
target_url
|
||||
}));
|
||||
}
|
||||
async getUnpublishedEntrySha(collection, slug) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collection, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
const mergeRequest = await this.getBranchMergeRequest(branch);
|
||||
return mergeRequest.sha;
|
||||
}
|
||||
}
|
||||
exports.default = API;
|
||||
137
node_modules/decap-cms-backend-gitlab/dist/esm/AuthenticationPage.js
generated
vendored
Normal file
137
node_modules/decap-cms-backend-gitlab/dist/esm/AuthenticationPage.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _base = _interopRequireDefault(require("@emotion/styled/base"));
|
||||
var _react = _interopRequireDefault(require("react"));
|
||||
var _propTypes = _interopRequireDefault(require("prop-types"));
|
||||
var _decapCmsLibAuth = require("decap-cms-lib-auth");
|
||||
var _decapCmsUiDefault = require("decap-cms-ui-default");
|
||||
var _react2 = require("@emotion/react");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
||||
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
||||
function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
|
||||
const LoginButtonIcon = /*#__PURE__*/(0, _base.default)(_decapCmsUiDefault.Icon, {
|
||||
target: "e80yw6v0",
|
||||
label: "LoginButtonIcon"
|
||||
})(process.env.NODE_ENV === "production" ? {
|
||||
name: "1gnqu05",
|
||||
styles: "margin-right:18px"
|
||||
} : {
|
||||
name: "1gnqu05",
|
||||
styles: "margin-right:18px",
|
||||
map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9BdXRoZW50aWNhdGlvblBhZ2UuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVW9DIiwiZmlsZSI6Ii4uLy4uL3NyYy9BdXRoZW50aWNhdGlvblBhZ2UuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcbmltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJztcbmltcG9ydCB7XG4gIE5ldGxpZnlBdXRoZW50aWNhdG9yLFxuICBJbXBsaWNpdEF1dGhlbnRpY2F0b3IsXG4gIFBrY2VBdXRoZW50aWNhdG9yLFxufSBmcm9tICdkZWNhcC1jbXMtbGliLWF1dGgnO1xuaW1wb3J0IHsgQXV0aGVudGljYXRpb25QYWdlLCBJY29uIH0gZnJvbSAnZGVjYXAtY21zLXVpLWRlZmF1bHQnO1xuXG5jb25zdCBMb2dpbkJ1dHRvbkljb24gPSBzdHlsZWQoSWNvbilgXG4gIG1hcmdpbi1yaWdodDogMThweDtcbmA7XG5cbmNvbnN0IGNsaWVudFNpZGVBdXRoZW50aWNhdG9ycyA9IHtcbiAgcGtjZTogKHtcbiAgICBiYXNlX3VybCxcbiAgICBhdXRoX2VuZHBvaW50LFxuICAgIGFwcF9pZCxcbiAgICBhdXRoX3Rva2VuX2VuZHBvaW50fSkgPT5cbiAgICBuZXcgUGtjZUF1dGhlbnRpY2F0b3Ioe1xuICAgICAgYmFzZV91cmwsXG4gICAgICBhdXRoX2VuZHBvaW50LFxuICAgICAgYXBwX2lkLFxuICAgICAgYXV0aF90b2tlbl9lbmRwb2ludCxcbiAgICAgIGF1dGhfdG9rZW5fZW5kcG9pbnRfY29udGVudF90eXBlOiAnYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOCcsXG4gICAgfSksXG5cbiAgaW1wbGljaXQ6ICh7XG4gICAgYmFzZV91cmwsXG4gICAgYXV0aF9lbmRwb2ludCxcbiAgICBhcHBfaWQsXG4gICAgY2xlYXJIYXNoIH0pID0+XG4gICAgbmV3IEltcGxpY2l0QXV0aGVudGljYXRvcih7XG4gICAgICBiYXNlX3VybCxcbiAgICAgIGF1dGhfZW5kcG9pbnQsXG4gICAgICBhcHBfaWQsXG4gICAgICBjbGVhckhhc2gsXG4gICAgfSksXG59O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBHaXRMYWJBdXRoZW50aWNhdGlvblBhZ2UgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICBzdGF0aWMgcHJvcFR5cGVzID0ge1xuICAgIG9uTG9naW46IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gICAgaW5Qcm9ncmVzczogUHJvcFR5cGVzLmJvb2wsXG4gICAgYmFzZV91cmw6IFByb3BUeXBlcy5zdHJpbmcsXG4gICAgc2l0ZUlkOiBQcm9wVHlwZXMuc3RyaW5nLFxuICAgIGF1dGhFbmRwb2ludDogUHJvcFR5cGVzLnN0cmluZyxcbiAgICBjb25maWc6IFByb3BUeXBlcy5vYmplY3QuaXNSZXF1aXJlZCxcbiAgICBjbGVhckhhc2g6IFByb3BUeXBlcy5mdW5jLFxuICAgIHQ6IFByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG4gIH07XG5cbiAgc3RhdGUgPSB7fTtcblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICBjb25zdCB7XG4gICAgICBhdXRoX3R5cGU6IGF1dGhUeXBlID0gJycsXG4gICAgICBiYXNlX3VybCA9ICdodHRwczovL2dpdGxhYi5jb20nLFxuICAgICAgYXV0aF9lbmRwb2ludCA9ICdvYXV0aC9hdXRob3JpemUnLFxuICAgICAgYXBwX2lkID0gJycsXG4gICAgfSA9IHRoaXMucHJvcHMuY29uZmlnLmJhY2tlbmQ7XG5cbiAgICBpZiAoY2xpZW50U2lkZUF1dGhlbnRpY2F0b3JzW2F1dGhUeXBlXSkge1xuICAgICAgdGhpcy5hdXRoID0gY2xpZW50U2lkZUF1dGhlbnRpY2F0b3JzW2F1dGhUeXBlXSh7XG4gICAgICAgIGJhc2VfdXJsLFxuICAgICAgICBhdXRoX2VuZHBvaW50LFxuICAgICAgICBhcHBfaWQsXG4gICAgICAgIGF1dGhfdG9rZW5fZW5kcG9pbnQ6ICdvYXV0aC90b2tlbicsXG4gICAgICAgIGNsZWFySGFzaDogdGhpcy5wcm9wcy5jbGVhckhhc2gsXG4gICAgICB9KTtcbiAgICAgIC8vIENvbXBsZXRlIGltcGxpY2l0IGF1dGhlbnRpY2F0aW9uIGlmIHdlIHdlcmUgcmVkaXJlY3RlZCBiYWNrIHRvIGZyb20gdGhlIHByb3ZpZGVyLlxuICAgICAgdGhpcy5hdXRoLmNvbXBsZXRlQXV0aCgoZXJyLCBkYXRhKSA9PiB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgbG9naW5FcnJvcjogZXJyLnRvU3RyaW5nKCkgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucHJvcHMub25Mb2dpbihkYXRhKTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmF1dGggPSBuZXcgTmV0bGlmeUF1dGhlbnRpY2F0b3Ioe1xuICAgICAgICBiYXNlX3VybDogdGhpcy5wcm9wcy5iYXNlX3VybCxcbiAgICAgICAgc2l0ZV9pZDpcbiAgICAgICAgICBkb2N1bWVudC5sb2NhdGlvbi5ob3N0LnNwbGl0KCc6JylbMF0gPT09ICdsb2NhbGhvc3QnXG4gICAgICAgICAgICA/ICdkZW1vLmRlY2FwY21zLm9yZydcbiAgICAgICAgICAgIDogdGhpcy5wcm9wcy5zaXRlSWQsXG4gICAgICAgIGF1dGhfZW5kcG9pbnQ6IHRoaXMucHJvcHMuYXV0aEVuZHBvaW50LFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlTG9naW4gPSBlID0+IHtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgdGhpcy5hdXRoLmF1dGhlbnRpY2F0ZSh7IHByb3ZpZGVyOiAnZ2l0bGFiJywgc2NvcGU6ICdhcGknIH0sIChlcnIsIGRhdGEpID0+IHtcbiAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGxvZ2luRXJyb3I6IGVyci50b1N0cmluZygpIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLnByb3BzLm9uTG9naW4oZGF0YSk7XG4gICAgfSk7XG4gIH07XG5cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IHsgaW5Qcm9ncmVzcywgY29uZmlnLCB0IH0gPSB0aGlzLnByb3BzO1xuICAgIHJldHVybiAoXG4gICAgICA8QXV0aGVudGljYXRpb25QYWdlXG4gICAgICAgIG9uTG9naW49e3RoaXMuaGFuZGxlTG9naW59XG4gICAgICAgIGxvZ2luRGlzYWJsZWQ9e2luUHJvZ3Jlc3N9XG4gICAgICAgIGxvZ2luRXJyb3JNZXNzYWdlPXt0aGlzLnN0YXRlLmxvZ2luRXJyb3J9XG4gICAgICAgIGxvZ29Vcmw9e2NvbmZpZy5sb2dvX3VybH1cbiAgICAgICAgc2l0ZVVybD17Y29uZmlnLnNpdGVfdXJsfVxuICAgICAgICByZW5kZXJCdXR0b25Db250ZW50PXsoKSA9PiAoXG4gICAgICAgICAgPFJlYWN0LkZyYWdtZW50PlxuICAgICAgICAgICAgPExvZ2luQnV0dG9uSWNvbiB0eXBlPVwiZ2l0bGFiXCIgLz57JyAnfVxuICAgICAgICAgICAge2luUHJvZ3Jlc3MgPyB0KCdhdXRoLmxvZ2dpbmdJbicpIDogdCgnYXV0aC5sb2dpbldpdGhHaXRMYWInKX1cbiAgICAgICAgICA8L1JlYWN0LkZyYWdtZW50PlxuICAgICAgICApfVxuICAgICAgICB0PXt0fVxuICAgICAgLz5cbiAgICApO1xuICB9XG59XG4iXX0= */",
|
||||
toString: _EMOTION_STRINGIFIED_CSS_ERROR__
|
||||
});
|
||||
const clientSideAuthenticators = {
|
||||
pkce: ({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint
|
||||
}) => new _decapCmsLibAuth.PkceAuthenticator({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint,
|
||||
auth_token_endpoint_content_type: 'application/json; charset=utf-8'
|
||||
}),
|
||||
implicit: ({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
clearHash
|
||||
}) => new _decapCmsLibAuth.ImplicitAuthenticator({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
clearHash
|
||||
})
|
||||
};
|
||||
class GitLabAuthenticationPage extends _react.default.Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
_defineProperty(this, "state", {});
|
||||
_defineProperty(this, "handleLogin", e => {
|
||||
e.preventDefault();
|
||||
this.auth.authenticate({
|
||||
provider: 'gitlab',
|
||||
scope: 'api'
|
||||
}, (err, data) => {
|
||||
if (err) {
|
||||
this.setState({
|
||||
loginError: err.toString()
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.props.onLogin(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
const {
|
||||
auth_type: authType = '',
|
||||
base_url = 'https://gitlab.com',
|
||||
auth_endpoint = 'oauth/authorize',
|
||||
app_id = ''
|
||||
} = this.props.config.backend;
|
||||
if (clientSideAuthenticators[authType]) {
|
||||
this.auth = clientSideAuthenticators[authType]({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint: 'oauth/token',
|
||||
clearHash: this.props.clearHash
|
||||
});
|
||||
// Complete implicit authentication if we were redirected back to from the provider.
|
||||
this.auth.completeAuth((err, data) => {
|
||||
if (err) {
|
||||
this.setState({
|
||||
loginError: err.toString()
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.props.onLogin(data);
|
||||
});
|
||||
} else {
|
||||
this.auth = new _decapCmsLibAuth.NetlifyAuthenticator({
|
||||
base_url: this.props.base_url,
|
||||
site_id: document.location.host.split(':')[0] === 'localhost' ? 'demo.decapcms.org' : this.props.siteId,
|
||||
auth_endpoint: this.props.authEndpoint
|
||||
});
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
inProgress,
|
||||
config,
|
||||
t
|
||||
} = this.props;
|
||||
return (0, _react2.jsx)(_decapCmsUiDefault.AuthenticationPage, {
|
||||
onLogin: this.handleLogin,
|
||||
loginDisabled: inProgress,
|
||||
loginErrorMessage: this.state.loginError,
|
||||
logoUrl: config.logo_url,
|
||||
siteUrl: config.site_url,
|
||||
renderButtonContent: () => (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)(LoginButtonIcon, {
|
||||
type: "gitlab"
|
||||
}), ' ', inProgress ? t('auth.loggingIn') : t('auth.loginWithGitLab')),
|
||||
t: t
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.default = GitLabAuthenticationPage;
|
||||
_defineProperty(GitLabAuthenticationPage, "propTypes", {
|
||||
onLogin: _propTypes.default.func.isRequired,
|
||||
inProgress: _propTypes.default.bool,
|
||||
base_url: _propTypes.default.string,
|
||||
siteId: _propTypes.default.string,
|
||||
authEndpoint: _propTypes.default.string,
|
||||
config: _propTypes.default.object.isRequired,
|
||||
clearHash: _propTypes.default.func,
|
||||
t: _propTypes.default.func.isRequired
|
||||
});
|
||||
388
node_modules/decap-cms-backend-gitlab/dist/esm/implementation.js
generated
vendored
Normal file
388
node_modules/decap-cms-backend-gitlab/dist/esm/implementation.js
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _trim2 = _interopRequireDefault(require("lodash/trim"));
|
||||
var _trimStart = _interopRequireDefault(require("lodash/trimStart"));
|
||||
var _semaphore = _interopRequireDefault(require("semaphore"));
|
||||
var _commonTags = require("common-tags");
|
||||
var _decapCmsLibUtil = require("decap-cms-lib-util");
|
||||
var _AuthenticationPage = _interopRequireDefault(require("./AuthenticationPage"));
|
||||
var _API = _interopRequireWildcard(require("./API"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
||||
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
||||
const MAX_CONCURRENT_DOWNLOADS = 10;
|
||||
class GitLab {
|
||||
constructor(config, options = {}) {
|
||||
_defineProperty(this, "lock", void 0);
|
||||
_defineProperty(this, "api", void 0);
|
||||
_defineProperty(this, "options", void 0);
|
||||
_defineProperty(this, "repo", void 0);
|
||||
_defineProperty(this, "isBranchConfigured", void 0);
|
||||
_defineProperty(this, "branch", void 0);
|
||||
_defineProperty(this, "apiRoot", void 0);
|
||||
_defineProperty(this, "token", void 0);
|
||||
_defineProperty(this, "squashMerges", void 0);
|
||||
_defineProperty(this, "cmsLabelPrefix", void 0);
|
||||
_defineProperty(this, "mediaFolder", void 0);
|
||||
_defineProperty(this, "previewContext", void 0);
|
||||
_defineProperty(this, "useGraphQL", void 0);
|
||||
_defineProperty(this, "graphQLAPIRoot", void 0);
|
||||
_defineProperty(this, "_mediaDisplayURLSem", void 0);
|
||||
this.options = _objectSpread({
|
||||
proxied: false,
|
||||
API: null,
|
||||
initialWorkflowStatus: ''
|
||||
}, options);
|
||||
if (!this.options.proxied && (config.backend.repo === null || config.backend.repo === undefined)) {
|
||||
throw new Error('The GitLab backend needs a "repo" in the backend configuration.');
|
||||
}
|
||||
this.api = this.options.API || null;
|
||||
this.repo = config.backend.repo || '';
|
||||
this.branch = config.backend.branch || 'master';
|
||||
this.isBranchConfigured = config.backend.branch ? true : false;
|
||||
this.apiRoot = config.backend.api_root || 'https://gitlab.com/api/v4';
|
||||
this.token = '';
|
||||
this.squashMerges = config.backend.squash_merges || false;
|
||||
this.cmsLabelPrefix = config.backend.cms_label_prefix || '';
|
||||
this.mediaFolder = config.media_folder;
|
||||
this.previewContext = config.backend.preview_context || '';
|
||||
this.useGraphQL = config.backend.use_graphql || false;
|
||||
this.graphQLAPIRoot = config.backend.graphql_api_root || 'https://gitlab.com/api/graphql';
|
||||
this.lock = (0, _decapCmsLibUtil.asyncLock)();
|
||||
}
|
||||
isGitBackend() {
|
||||
return true;
|
||||
}
|
||||
async status() {
|
||||
var _this$api;
|
||||
const auth = (await ((_this$api = this.api) === null || _this$api === void 0 ? void 0 : _this$api.user().then(user => !!user).catch(e => {
|
||||
console.warn('Failed getting GitLab user', e);
|
||||
return false;
|
||||
}))) || false;
|
||||
return {
|
||||
auth: {
|
||||
status: auth
|
||||
},
|
||||
api: {
|
||||
status: true,
|
||||
statusPage: ''
|
||||
}
|
||||
};
|
||||
}
|
||||
authComponent() {
|
||||
return _AuthenticationPage.default;
|
||||
}
|
||||
restoreUser(user) {
|
||||
return this.authenticate(user);
|
||||
}
|
||||
async authenticate(state) {
|
||||
this.token = state.token;
|
||||
this.api = new _API.default({
|
||||
token: this.token,
|
||||
branch: this.branch,
|
||||
repo: this.repo,
|
||||
apiRoot: this.apiRoot,
|
||||
squashMerges: this.squashMerges,
|
||||
cmsLabelPrefix: this.cmsLabelPrefix,
|
||||
initialWorkflowStatus: this.options.initialWorkflowStatus,
|
||||
useGraphQL: this.useGraphQL,
|
||||
graphQLAPIRoot: this.graphQLAPIRoot
|
||||
});
|
||||
const user = await this.api.user();
|
||||
const isCollab = await this.api.hasWriteAccess().catch(error => {
|
||||
error.message = (0, _commonTags.stripIndent)`
|
||||
Repo "${this.repo}" not found.
|
||||
|
||||
Please ensure the repo information is spelled correctly.
|
||||
|
||||
If the repo is private, make sure you're logged into a GitLab account with access.
|
||||
`;
|
||||
throw error;
|
||||
});
|
||||
|
||||
// Unauthorized user
|
||||
if (!isCollab) {
|
||||
throw new Error('Your GitLab user account does not have access to this repo.');
|
||||
}
|
||||
if (!this.isBranchConfigured) {
|
||||
const defaultBranchName = await (0, _decapCmsLibUtil.getDefaultBranchName)({
|
||||
backend: 'gitlab',
|
||||
repo: this.repo,
|
||||
token: this.token,
|
||||
apiRoot: this.apiRoot
|
||||
});
|
||||
if (defaultBranchName) {
|
||||
this.branch = defaultBranchName;
|
||||
}
|
||||
}
|
||||
// Authorized user
|
||||
return _objectSpread(_objectSpread({}, user), {}, {
|
||||
login: user.username,
|
||||
token: state.token
|
||||
});
|
||||
}
|
||||
async logout() {
|
||||
this.token = null;
|
||||
return;
|
||||
}
|
||||
getToken() {
|
||||
return Promise.resolve(this.token);
|
||||
}
|
||||
filterFile(folder, file, extension, depth) {
|
||||
// gitlab paths include the root folder
|
||||
const fileFolder = (0, _trim2.default)(file.path.split(folder)[1] || '/', '/');
|
||||
return (0, _decapCmsLibUtil.filterByExtension)(file, extension) && fileFolder.split('/').length <= depth;
|
||||
}
|
||||
async entriesByFolder(folder, extension, depth) {
|
||||
let cursor;
|
||||
const listFiles = () => this.api.listFiles(folder, depth > 1).then(({
|
||||
files,
|
||||
cursor: c
|
||||
}) => {
|
||||
cursor = c.mergeMeta({
|
||||
folder,
|
||||
extension,
|
||||
depth
|
||||
});
|
||||
return files.filter(file => this.filterFile(folder, file, extension, depth));
|
||||
});
|
||||
const files = await (0, _decapCmsLibUtil.entriesByFolder)(listFiles, this.api.readFile.bind(this.api), this.api.readFileMetadata.bind(this.api), _API.API_NAME);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
files[_decapCmsLibUtil.CURSOR_COMPATIBILITY_SYMBOL] = cursor;
|
||||
return files;
|
||||
}
|
||||
async listAllFiles(folder, extension, depth) {
|
||||
const files = await this.api.listAllFiles(folder, depth > 1);
|
||||
const filtered = files.filter(file => this.filterFile(folder, file, extension, depth));
|
||||
return filtered;
|
||||
}
|
||||
async allEntriesByFolder(folder, extension, depth) {
|
||||
const files = await (0, _decapCmsLibUtil.allEntriesByFolder)({
|
||||
listAllFiles: () => this.listAllFiles(folder, extension, depth),
|
||||
readFile: this.api.readFile.bind(this.api),
|
||||
readFileMetadata: this.api.readFileMetadata.bind(this.api),
|
||||
apiName: _API.API_NAME,
|
||||
branch: this.branch,
|
||||
localForage: _decapCmsLibUtil.localForage,
|
||||
folder,
|
||||
extension,
|
||||
depth,
|
||||
getDefaultBranch: () => this.api.getDefaultBranch().then(b => ({
|
||||
name: b.name,
|
||||
sha: b.commit.id
|
||||
})),
|
||||
isShaExistsInBranch: this.api.isShaExistsInBranch.bind(this.api),
|
||||
getDifferences: (to, from) => this.api.getDifferences(to, from),
|
||||
getFileId: path => this.api.getFileId(path, this.branch),
|
||||
filterFile: file => this.filterFile(folder, file, extension, depth),
|
||||
customFetch: this.useGraphQL ? files => this.api.readFilesGraphQL(files) : undefined
|
||||
});
|
||||
return files;
|
||||
}
|
||||
entriesByFiles(files) {
|
||||
return (0, _decapCmsLibUtil.entriesByFiles)(files, this.api.readFile.bind(this.api), this.api.readFileMetadata.bind(this.api), _API.API_NAME);
|
||||
}
|
||||
|
||||
// Fetches a single entry.
|
||||
getEntry(path) {
|
||||
return this.api.readFile(path).then(data => ({
|
||||
file: {
|
||||
path,
|
||||
id: null
|
||||
},
|
||||
data: data
|
||||
}));
|
||||
}
|
||||
getMedia(mediaFolder = this.mediaFolder) {
|
||||
return this.api.listAllFiles(mediaFolder).then(files => files.map(({
|
||||
id,
|
||||
name,
|
||||
path
|
||||
}) => {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
displayURL: {
|
||||
id,
|
||||
name,
|
||||
path
|
||||
}
|
||||
};
|
||||
}));
|
||||
}
|
||||
getMediaDisplayURL(displayURL) {
|
||||
this._mediaDisplayURLSem = this._mediaDisplayURLSem || (0, _semaphore.default)(MAX_CONCURRENT_DOWNLOADS);
|
||||
return (0, _decapCmsLibUtil.getMediaDisplayURL)(displayURL, this.api.readFile.bind(this.api), this._mediaDisplayURLSem);
|
||||
}
|
||||
async getMediaFile(path) {
|
||||
const name = (0, _decapCmsLibUtil.basename)(path);
|
||||
const blob = await (0, _decapCmsLibUtil.getMediaAsBlob)(path, null, this.api.readFile.bind(this.api));
|
||||
const fileObj = (0, _decapCmsLibUtil.blobToFileObj)(name, blob);
|
||||
const url = URL.createObjectURL(fileObj);
|
||||
const id = await (0, _decapCmsLibUtil.getBlobSHA)(blob);
|
||||
return {
|
||||
id,
|
||||
displayURL: url,
|
||||
path,
|
||||
name,
|
||||
size: fileObj.size,
|
||||
file: fileObj,
|
||||
url
|
||||
};
|
||||
}
|
||||
async persistEntry(entry, options) {
|
||||
// persistEntry is a transactional operation
|
||||
return (0, _decapCmsLibUtil.runWithLock)(this.lock, () => this.api.persistFiles(entry.dataFiles, entry.assets, options), 'Failed to acquire persist entry lock');
|
||||
}
|
||||
async persistMedia(mediaFile, options) {
|
||||
const fileObj = mediaFile.fileObj;
|
||||
const [id] = await Promise.all([(0, _decapCmsLibUtil.getBlobSHA)(fileObj), this.api.persistFiles([], [mediaFile], options)]);
|
||||
const {
|
||||
path
|
||||
} = mediaFile;
|
||||
const url = URL.createObjectURL(fileObj);
|
||||
return {
|
||||
displayURL: url,
|
||||
path: (0, _trimStart.default)(path, '/'),
|
||||
name: fileObj.name,
|
||||
size: fileObj.size,
|
||||
file: fileObj,
|
||||
url,
|
||||
id
|
||||
};
|
||||
}
|
||||
deleteFiles(paths, commitMessage) {
|
||||
return this.api.deleteFiles(paths, commitMessage);
|
||||
}
|
||||
traverseCursor(cursor, action) {
|
||||
return this.api.traverseCursor(cursor, action).then(async ({
|
||||
entries,
|
||||
cursor: newCursor
|
||||
}) => {
|
||||
var _cursor$meta, _cursor$meta2, _cursor$meta3;
|
||||
const [folder, depth, extension] = [(_cursor$meta = cursor.meta) === null || _cursor$meta === void 0 ? void 0 : _cursor$meta.get('folder'), (_cursor$meta2 = cursor.meta) === null || _cursor$meta2 === void 0 ? void 0 : _cursor$meta2.get('depth'), (_cursor$meta3 = cursor.meta) === null || _cursor$meta3 === void 0 ? void 0 : _cursor$meta3.get('extension')];
|
||||
if (folder && depth && extension) {
|
||||
entries = entries.filter(f => this.filterFile(folder, f, extension, depth));
|
||||
newCursor = newCursor.mergeMeta({
|
||||
folder,
|
||||
extension,
|
||||
depth
|
||||
});
|
||||
}
|
||||
const entriesWithData = await (0, _decapCmsLibUtil.entriesByFiles)(entries, this.api.readFile.bind(this.api), this.api.readFileMetadata.bind(this.api), _API.API_NAME);
|
||||
return {
|
||||
entries: entriesWithData,
|
||||
cursor: newCursor
|
||||
};
|
||||
});
|
||||
}
|
||||
loadMediaFile(branch, file) {
|
||||
const readFile = (path, id, {
|
||||
parseText
|
||||
}) => this.api.readFile(path, id, {
|
||||
branch,
|
||||
parseText
|
||||
});
|
||||
return (0, _decapCmsLibUtil.getMediaAsBlob)(file.path, null, readFile).then(blob => {
|
||||
const name = (0, _decapCmsLibUtil.basename)(file.path);
|
||||
const fileObj = (0, _decapCmsLibUtil.blobToFileObj)(name, blob);
|
||||
return {
|
||||
id: file.path,
|
||||
displayURL: URL.createObjectURL(fileObj),
|
||||
path: file.path,
|
||||
name,
|
||||
size: fileObj.size,
|
||||
file: fileObj
|
||||
};
|
||||
});
|
||||
}
|
||||
async loadEntryMediaFiles(branch, files) {
|
||||
const mediaFiles = await Promise.all(files.map(file => this.loadMediaFile(branch, file)));
|
||||
return mediaFiles;
|
||||
}
|
||||
async unpublishedEntries() {
|
||||
const listEntriesKeys = () => this.api.listUnpublishedBranches().then(branches => branches.map(branch => (0, _decapCmsLibUtil.contentKeyFromBranch)(branch)));
|
||||
const ids = await (0, _decapCmsLibUtil.unpublishedEntries)(listEntriesKeys);
|
||||
return ids;
|
||||
}
|
||||
async unpublishedEntry({
|
||||
id,
|
||||
collection,
|
||||
slug
|
||||
}) {
|
||||
if (id) {
|
||||
const data = await this.api.retrieveUnpublishedEntryData(id);
|
||||
return data;
|
||||
} else if (collection && slug) {
|
||||
const entryId = (0, _decapCmsLibUtil.generateContentKey)(collection, slug);
|
||||
const data = await this.api.retrieveUnpublishedEntryData(entryId);
|
||||
return data;
|
||||
} else {
|
||||
throw new Error('Missing unpublished entry id or collection and slug');
|
||||
}
|
||||
}
|
||||
getBranch(collection, slug) {
|
||||
const contentKey = (0, _decapCmsLibUtil.generateContentKey)(collection, slug);
|
||||
const branch = (0, _decapCmsLibUtil.branchFromContentKey)(contentKey);
|
||||
return branch;
|
||||
}
|
||||
async unpublishedEntryDataFile(collection, slug, path, id) {
|
||||
const branch = this.getBranch(collection, slug);
|
||||
const data = await this.api.readFile(path, id, {
|
||||
branch
|
||||
});
|
||||
return data;
|
||||
}
|
||||
async unpublishedEntryMediaFile(collection, slug, path, id) {
|
||||
const branch = this.getBranch(collection, slug);
|
||||
const mediaFile = await this.loadMediaFile(branch, {
|
||||
path,
|
||||
id
|
||||
});
|
||||
return mediaFile;
|
||||
}
|
||||
async updateUnpublishedEntryStatus(collection, slug, newStatus) {
|
||||
// updateUnpublishedEntryStatus is a transactional operation
|
||||
return (0, _decapCmsLibUtil.runWithLock)(this.lock, () => this.api.updateUnpublishedEntryStatus(collection, slug, newStatus), 'Failed to acquire update entry status lock');
|
||||
}
|
||||
async deleteUnpublishedEntry(collection, slug) {
|
||||
// deleteUnpublishedEntry is a transactional operation
|
||||
return (0, _decapCmsLibUtil.runWithLock)(this.lock, () => this.api.deleteUnpublishedEntry(collection, slug), 'Failed to acquire delete entry lock');
|
||||
}
|
||||
async publishUnpublishedEntry(collection, slug) {
|
||||
// publishUnpublishedEntry is a transactional operation
|
||||
return (0, _decapCmsLibUtil.runWithLock)(this.lock, () => this.api.publishUnpublishedEntry(collection, slug), 'Failed to acquire publish entry lock');
|
||||
}
|
||||
async getDeployPreview(collection, slug) {
|
||||
try {
|
||||
const statuses = await this.api.getStatuses(collection, slug);
|
||||
const deployStatus = (0, _decapCmsLibUtil.getPreviewStatus)(statuses, this.previewContext);
|
||||
if (deployStatus) {
|
||||
const {
|
||||
target_url: url,
|
||||
state
|
||||
} = deployStatus;
|
||||
return {
|
||||
url,
|
||||
status: state
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = GitLab;
|
||||
33
node_modules/decap-cms-backend-gitlab/dist/esm/index.js
generated
vendored
Normal file
33
node_modules/decap-cms-backend-gitlab/dist/esm/index.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "API", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _API.default;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "AuthenticationPage", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _AuthenticationPage.default;
|
||||
}
|
||||
});
|
||||
exports.DecapCmsBackendGitlab = void 0;
|
||||
Object.defineProperty(exports, "GitLabBackend", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _implementation.default;
|
||||
}
|
||||
});
|
||||
var _implementation = _interopRequireDefault(require("./implementation"));
|
||||
var _API = _interopRequireDefault(require("./API"));
|
||||
var _AuthenticationPage = _interopRequireDefault(require("./AuthenticationPage"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const DecapCmsBackendGitlab = exports.DecapCmsBackendGitlab = {
|
||||
GitLabBackend: _implementation.default,
|
||||
API: _API.default,
|
||||
AuthenticationPage: _AuthenticationPage.default
|
||||
};
|
||||
71
node_modules/decap-cms-backend-gitlab/dist/esm/queries.js
generated
vendored
Normal file
71
node_modules/decap-cms-backend-gitlab/dist/esm/queries.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.files = exports.blobs = void 0;
|
||||
exports.lastCommits = lastCommits;
|
||||
var _graphqlTag = require("graphql-tag");
|
||||
var _commonTags = require("common-tags");
|
||||
const files = exports.files = (0, _graphqlTag.gql)`
|
||||
query files($repo: ID!, $branch: String!, $path: String!, $recursive: Boolean!, $cursor: String) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
tree(ref: $branch, path: $path, recursive: $recursive) {
|
||||
blobs(after: $cursor) {
|
||||
nodes {
|
||||
type
|
||||
id: sha
|
||||
path
|
||||
name
|
||||
}
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const blobs = exports.blobs = (0, _graphqlTag.gql)`
|
||||
query blobs($repo: ID!, $branch: String!, $paths: [String!]!) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
blobs(ref: $branch, paths: $paths) {
|
||||
nodes {
|
||||
id
|
||||
data: rawBlob
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
function lastCommits(paths) {
|
||||
const tree = paths.map((path, index) => (0, _commonTags.oneLine)`
|
||||
tree${index}: tree(ref: $branch, path: "${path}") {
|
||||
lastCommit {
|
||||
authorName
|
||||
authoredDate
|
||||
author {
|
||||
id
|
||||
username
|
||||
name
|
||||
publicEmail
|
||||
}
|
||||
}
|
||||
}
|
||||
`).join('\n');
|
||||
const query = (0, _graphqlTag.gql)`
|
||||
query lastCommits($repo: ID!, $branch: String!) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
${tree}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return query;
|
||||
}
|
||||
41
node_modules/decap-cms-backend-gitlab/package.json
generated
vendored
Normal file
41
node_modules/decap-cms-backend-gitlab/package.json
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "decap-cms-backend-gitlab",
|
||||
"description": "GitLab backend for Decap CMS",
|
||||
"version": "3.2.2",
|
||||
"repository": "https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-backend-gitlab",
|
||||
"bugs": "https://github.com/decaporg/decap-cms/issues",
|
||||
"license": "MIT",
|
||||
"module": "dist/esm/index.js",
|
||||
"main": "dist/decap-cms-backend-gitlab.js",
|
||||
"keywords": [
|
||||
"decap-cms",
|
||||
"backend",
|
||||
"gitlab"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"develop": "npm run build:esm -- --watch",
|
||||
"build": "cross-env NODE_ENV=production webpack",
|
||||
"build:esm": "cross-env NODE_ENV=esm babel src --out-dir dist/esm --ignore \"**/__tests__\" --root-mode upward --extensions \".js,.jsx,.ts,.tsx\""
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-cache-inmemory": "^1.6.2",
|
||||
"apollo-client": "^2.6.3",
|
||||
"apollo-link-context": "^1.0.18",
|
||||
"apollo-link-http": "^1.5.15",
|
||||
"js-base64": "^3.0.0",
|
||||
"semaphore": "^1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"decap-cms-lib-auth": "^3.0.0",
|
||||
"decap-cms-lib-util": "^3.0.0",
|
||||
"decap-cms-ui-default": "^3.0.0",
|
||||
"immutable": "^3.7.6",
|
||||
"lodash": "^4.17.11",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"gitHead": "64d91b8bb3d0a93dd36c53800cdac4ba2e435000"
|
||||
}
|
||||
1018
node_modules/decap-cms-backend-gitlab/src/API.ts
generated
vendored
Normal file
1018
node_modules/decap-cms-backend-gitlab/src/API.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
122
node_modules/decap-cms-backend-gitlab/src/AuthenticationPage.js
generated
vendored
Normal file
122
node_modules/decap-cms-backend-gitlab/src/AuthenticationPage.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
NetlifyAuthenticator,
|
||||
ImplicitAuthenticator,
|
||||
PkceAuthenticator,
|
||||
} from 'decap-cms-lib-auth';
|
||||
import { AuthenticationPage, Icon } from 'decap-cms-ui-default';
|
||||
|
||||
const LoginButtonIcon = styled(Icon)`
|
||||
margin-right: 18px;
|
||||
`;
|
||||
|
||||
const clientSideAuthenticators = {
|
||||
pkce: ({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint}) =>
|
||||
new PkceAuthenticator({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint,
|
||||
auth_token_endpoint_content_type: 'application/json; charset=utf-8',
|
||||
}),
|
||||
|
||||
implicit: ({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
clearHash }) =>
|
||||
new ImplicitAuthenticator({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
clearHash,
|
||||
}),
|
||||
};
|
||||
|
||||
export default class GitLabAuthenticationPage extends React.Component {
|
||||
static propTypes = {
|
||||
onLogin: PropTypes.func.isRequired,
|
||||
inProgress: PropTypes.bool,
|
||||
base_url: PropTypes.string,
|
||||
siteId: PropTypes.string,
|
||||
authEndpoint: PropTypes.string,
|
||||
config: PropTypes.object.isRequired,
|
||||
clearHash: PropTypes.func,
|
||||
t: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {};
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
auth_type: authType = '',
|
||||
base_url = 'https://gitlab.com',
|
||||
auth_endpoint = 'oauth/authorize',
|
||||
app_id = '',
|
||||
} = this.props.config.backend;
|
||||
|
||||
if (clientSideAuthenticators[authType]) {
|
||||
this.auth = clientSideAuthenticators[authType]({
|
||||
base_url,
|
||||
auth_endpoint,
|
||||
app_id,
|
||||
auth_token_endpoint: 'oauth/token',
|
||||
clearHash: this.props.clearHash,
|
||||
});
|
||||
// Complete implicit authentication if we were redirected back to from the provider.
|
||||
this.auth.completeAuth((err, data) => {
|
||||
if (err) {
|
||||
this.setState({ loginError: err.toString() });
|
||||
return;
|
||||
}
|
||||
this.props.onLogin(data);
|
||||
});
|
||||
} else {
|
||||
this.auth = new NetlifyAuthenticator({
|
||||
base_url: this.props.base_url,
|
||||
site_id:
|
||||
document.location.host.split(':')[0] === 'localhost'
|
||||
? 'demo.decapcms.org'
|
||||
: this.props.siteId,
|
||||
auth_endpoint: this.props.authEndpoint,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleLogin = e => {
|
||||
e.preventDefault();
|
||||
this.auth.authenticate({ provider: 'gitlab', scope: 'api' }, (err, data) => {
|
||||
if (err) {
|
||||
this.setState({ loginError: err.toString() });
|
||||
return;
|
||||
}
|
||||
this.props.onLogin(data);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { inProgress, config, t } = this.props;
|
||||
return (
|
||||
<AuthenticationPage
|
||||
onLogin={this.handleLogin}
|
||||
loginDisabled={inProgress}
|
||||
loginErrorMessage={this.state.loginError}
|
||||
logoUrl={config.logo_url}
|
||||
siteUrl={config.site_url}
|
||||
renderButtonContent={() => (
|
||||
<React.Fragment>
|
||||
<LoginButtonIcon type="gitlab" />{' '}
|
||||
{inProgress ? t('auth.loggingIn') : t('auth.loginWithGitLab')}
|
||||
</React.Fragment>
|
||||
)}
|
||||
t={t}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
187
node_modules/decap-cms-backend-gitlab/src/__tests__/API.spec.js
generated
vendored
Normal file
187
node_modules/decap-cms-backend-gitlab/src/__tests__/API.spec.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
import API, { getMaxAccess } from '../API';
|
||||
|
||||
global.fetch = jest.fn().mockRejectedValue(new Error('should not call fetch inside tests'));
|
||||
|
||||
jest.spyOn(console, 'log').mockImplementation(() => undefined);
|
||||
|
||||
describe('GitLab API', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('hasWriteAccess', () => {
|
||||
test('should return true on project access_level >= 30', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ permissions: { project_access: { access_level: 30 } } });
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(true);
|
||||
});
|
||||
|
||||
test('should return false on project access_level < 30', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ permissions: { project_access: { access_level: 10 } } });
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
});
|
||||
|
||||
test('should return true on group access_level >= 30', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ permissions: { group_access: { access_level: 30 } } });
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(true);
|
||||
});
|
||||
|
||||
test('should return false on group access_level < 30', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ permissions: { group_access: { access_level: 10 } } });
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
});
|
||||
|
||||
test('should return true on shared group access_level >= 40', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
api.requestJSON = jest.fn().mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 40 }],
|
||||
});
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(true);
|
||||
|
||||
expect(api.requestJSON).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should return true on shared group access_level >= 30, developers can merge and push', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest.fn();
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
|
||||
});
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
developers_can_merge: true,
|
||||
developers_can_push: true,
|
||||
});
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(true);
|
||||
});
|
||||
|
||||
test('should return false on shared group access_level < 30,', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest.fn();
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 20 }],
|
||||
});
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
developers_can_merge: true,
|
||||
developers_can_push: true,
|
||||
});
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
});
|
||||
|
||||
test("should return false on shared group access_level >= 30, developers can't merge", async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest.fn();
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
|
||||
});
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
developers_can_merge: false,
|
||||
developers_can_push: true,
|
||||
});
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
});
|
||||
|
||||
test("should return false on shared group access_level >= 30, developers can't push", async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest.fn();
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
|
||||
});
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
developers_can_merge: true,
|
||||
developers_can_push: false,
|
||||
});
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
});
|
||||
|
||||
test('should return false on shared group access_level >= 30, error getting branch', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
api.requestJSON = jest.fn();
|
||||
api.requestJSON.mockResolvedValueOnce({
|
||||
permissions: { project_access: null, group_access: null },
|
||||
shared_with_groups: [{ group_access_level: 10 }, { group_access_level: 30 }],
|
||||
});
|
||||
|
||||
const error = new Error('Not Found');
|
||||
api.requestJSON.mockRejectedValue(error);
|
||||
|
||||
await expect(api.hasWriteAccess()).resolves.toBe(false);
|
||||
|
||||
expect(console.log).toHaveBeenCalledTimes(1);
|
||||
expect(console.log).toHaveBeenCalledWith('Failed getting default branch', error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStatuses', () => {
|
||||
test('should get preview statuses', async () => {
|
||||
const api = new API({ repo: 'repo' });
|
||||
|
||||
const mr = { sha: 'sha' };
|
||||
const statuses = [
|
||||
{ name: 'deploy', status: 'success', target_url: 'deploy-url' },
|
||||
{ name: 'build', status: 'pending' },
|
||||
];
|
||||
|
||||
api.getBranchMergeRequest = jest.fn(() => Promise.resolve(mr));
|
||||
api.getMergeRequestStatues = jest.fn(() => Promise.resolve(statuses));
|
||||
|
||||
const collectionName = 'posts';
|
||||
const slug = 'title';
|
||||
await expect(api.getStatuses(collectionName, slug)).resolves.toEqual([
|
||||
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
|
||||
{ context: 'build', state: 'other' },
|
||||
]);
|
||||
|
||||
expect(api.getBranchMergeRequest).toHaveBeenCalledTimes(1);
|
||||
expect(api.getBranchMergeRequest).toHaveBeenCalledWith('cms/posts/title');
|
||||
|
||||
expect(api.getMergeRequestStatues).toHaveBeenCalledTimes(1);
|
||||
expect(api.getMergeRequestStatues).toHaveBeenCalledWith(mr, 'cms/posts/title');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMaxAccess', () => {
|
||||
it('should return group with max access level', () => {
|
||||
const groups = [
|
||||
{ group_access_level: 10 },
|
||||
{ group_access_level: 5 },
|
||||
{ group_access_level: 100 },
|
||||
{ group_access_level: 1 },
|
||||
];
|
||||
expect(getMaxAccess(groups)).toBe(groups[2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
552
node_modules/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js
generated
vendored
Normal file
552
node_modules/decap-cms-backend-gitlab/src/__tests__/gitlab.spec.js
generated
vendored
Normal file
@@ -0,0 +1,552 @@
|
||||
jest.mock('decap-cms-core/src/backend');
|
||||
import { fromJS } from 'immutable';
|
||||
import { oneLine, stripIndent } from 'common-tags';
|
||||
import nock from 'nock';
|
||||
import { Cursor } from 'decap-cms-lib-util';
|
||||
|
||||
import Gitlab from '../implementation';
|
||||
import AuthenticationPage from '../AuthenticationPage';
|
||||
|
||||
const { Backend, LocalStorageAuthStore } = jest.requireActual('decap-cms-core/src/backend');
|
||||
|
||||
function generateEntries(path, length) {
|
||||
const entries = Array.from({ length }, (val, idx) => {
|
||||
const count = idx + 1;
|
||||
const id = `00${count}`.slice(-3);
|
||||
const fileName = `test${id}.md`;
|
||||
return { id, fileName, filePath: `${path}/${fileName}` };
|
||||
});
|
||||
|
||||
return {
|
||||
tree: entries.map(({ id, fileName, filePath }) => ({
|
||||
id: `d8345753a1d935fa47a26317a503e73e1192d${id}`,
|
||||
name: fileName,
|
||||
type: 'blob',
|
||||
path: filePath,
|
||||
mode: '100644',
|
||||
})),
|
||||
files: entries.reduce(
|
||||
(acc, { id, filePath }) => ({
|
||||
...acc,
|
||||
[filePath]: stripIndent`
|
||||
---
|
||||
title: test ${id}
|
||||
---
|
||||
# test ${id}
|
||||
`,
|
||||
}),
|
||||
{},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const manyEntries = generateEntries('many-entries', 500);
|
||||
|
||||
const mockRepo = {
|
||||
tree: {
|
||||
'/': [
|
||||
{
|
||||
id: '5d0620ebdbc92068a3e866866e928cc373f18429',
|
||||
name: 'content',
|
||||
type: 'tree',
|
||||
path: 'content',
|
||||
mode: '040000',
|
||||
},
|
||||
],
|
||||
content: [
|
||||
{
|
||||
id: 'b1a200e48be54fde12b636f9563d659d44c206a5',
|
||||
name: 'test1.md',
|
||||
type: 'blob',
|
||||
path: 'content/test1.md',
|
||||
mode: '100644',
|
||||
},
|
||||
{
|
||||
id: 'd8345753a1d935fa47a26317a503e73e1192d623',
|
||||
name: 'test2.md',
|
||||
type: 'blob',
|
||||
path: 'content/test2.md',
|
||||
mode: '100644',
|
||||
},
|
||||
],
|
||||
'many-entries': manyEntries.tree,
|
||||
},
|
||||
files: {
|
||||
'content/test1.md': stripIndent`
|
||||
---
|
||||
title: test
|
||||
---
|
||||
# test
|
||||
`,
|
||||
'content/test2.md': stripIndent`
|
||||
---
|
||||
title: test2
|
||||
---
|
||||
# test 2
|
||||
`,
|
||||
...manyEntries.files,
|
||||
},
|
||||
};
|
||||
|
||||
const resp = {
|
||||
user: {
|
||||
success: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
branch: {
|
||||
success: {
|
||||
name: 'master',
|
||||
commit: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
project: {
|
||||
success: {
|
||||
permissions: {
|
||||
project_access: {
|
||||
access_level: 30,
|
||||
},
|
||||
},
|
||||
default_branch: 'main',
|
||||
},
|
||||
readOnly: {
|
||||
permissions: {
|
||||
project_access: {
|
||||
access_level: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('gitlab backend', () => {
|
||||
let authStore;
|
||||
let backend;
|
||||
const repo = 'foo/bar';
|
||||
const defaultConfig = {
|
||||
backend: {
|
||||
name: 'gitlab',
|
||||
repo,
|
||||
},
|
||||
};
|
||||
const collectionContentConfig = {
|
||||
name: 'foo',
|
||||
folder: 'content',
|
||||
fields: [{ name: 'title' }],
|
||||
// TODO: folder_based_collection is an internal string, we should not
|
||||
// be depending on it here
|
||||
type: 'folder_based_collection',
|
||||
};
|
||||
const collectionManyEntriesConfig = {
|
||||
name: 'foo',
|
||||
folder: 'many-entries',
|
||||
fields: [{ name: 'title' }],
|
||||
// TODO: folder_based_collection is an internal string, we should not
|
||||
// be depending on it here
|
||||
type: 'folder_based_collection',
|
||||
};
|
||||
const collectionFilesConfig = {
|
||||
name: 'foo',
|
||||
files: [
|
||||
{
|
||||
label: 'foo',
|
||||
name: 'foo',
|
||||
file: 'content/test1.md',
|
||||
fields: [{ name: 'title' }],
|
||||
},
|
||||
{
|
||||
label: 'bar',
|
||||
name: 'bar',
|
||||
file: 'content/test2.md',
|
||||
fields: [{ name: 'title' }],
|
||||
},
|
||||
],
|
||||
type: 'file_based_collection',
|
||||
};
|
||||
const mockCredentials = { token: 'MOCK_TOKEN' };
|
||||
const expectedRepo = encodeURIComponent(repo);
|
||||
const expectedRepoUrl = `/projects/${expectedRepo}`;
|
||||
|
||||
function resolveBackend(config = {}) {
|
||||
authStore = new LocalStorageAuthStore();
|
||||
return new Backend(
|
||||
{
|
||||
init: (...args) => new Gitlab(...args),
|
||||
},
|
||||
{
|
||||
backendName: 'gitlab',
|
||||
config,
|
||||
authStore,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function mockApi(backend) {
|
||||
return nock(backend.implementation.apiRoot);
|
||||
}
|
||||
|
||||
function interceptAuth(backend, { userResponse, projectResponse } = {}) {
|
||||
const api = mockApi(backend);
|
||||
api
|
||||
.get('/user')
|
||||
.query(true)
|
||||
.reply(200, userResponse || resp.user.success);
|
||||
|
||||
api
|
||||
// The `authenticate` method of the API class from netlify-cms-backend-gitlab
|
||||
// calls the same endpoint twice for gettng a single project.
|
||||
// First time through `this.api.hasWriteAccess()
|
||||
// Second time through the method `getDefaultBranchName` from lib-util
|
||||
// As a result, we need to repeat the same response twice.
|
||||
// Otherwise, we'll get an error: "No match for request to
|
||||
// https://gitlab.com/api/v4"
|
||||
|
||||
.get(expectedRepoUrl)
|
||||
.times(2)
|
||||
.query(true)
|
||||
.reply(200, projectResponse || resp.project.success);
|
||||
}
|
||||
|
||||
function interceptBranch(backend, { branch = 'master' } = {}) {
|
||||
const api = mockApi(backend);
|
||||
api
|
||||
.get(`${expectedRepoUrl}/repository/branches/${encodeURIComponent(branch)}`)
|
||||
.query(true)
|
||||
.reply(200, resp.branch.success);
|
||||
}
|
||||
|
||||
function parseQuery(uri) {
|
||||
const query = uri.split('?')[1];
|
||||
if (!query) {
|
||||
return {};
|
||||
}
|
||||
return query.split('&').reduce((acc, q) => {
|
||||
const [key, value] = q.split('=');
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function createHeaders(backend, { basePath, path, page, perPage, pageCount, totalCount }) {
|
||||
const pageNum = parseInt(page, 10);
|
||||
const pageCountNum = parseInt(pageCount, 10);
|
||||
const url = `${backend.implementation.apiRoot}${basePath}`;
|
||||
|
||||
function link(linkPage) {
|
||||
return `<${url}?id=${expectedRepo}&page=${linkPage}&path=${path}&per_page=${perPage}&recursive=false>`;
|
||||
}
|
||||
|
||||
const linkHeader = oneLine`
|
||||
${link(1)}; rel="first",
|
||||
${link(pageCount)}; rel="last",
|
||||
${pageNum === 1 ? '' : `${link(pageNum - 1)}; rel="prev",`}
|
||||
${pageNum === pageCountNum ? '' : `${link(pageNum + 1)}; rel="next",`}
|
||||
`.slice(0, -1);
|
||||
|
||||
return {
|
||||
'X-Page': page,
|
||||
'X-Total-Pages': pageCount,
|
||||
'X-Per-Page': perPage,
|
||||
'X-Total': totalCount,
|
||||
Link: linkHeader,
|
||||
};
|
||||
}
|
||||
|
||||
function interceptCollection(
|
||||
backend,
|
||||
collection,
|
||||
{ verb = 'get', repeat = 1, page: expectedPage } = {},
|
||||
) {
|
||||
const api = mockApi(backend);
|
||||
const url = `${expectedRepoUrl}/repository/tree`;
|
||||
const { folder } = collection;
|
||||
const tree = mockRepo.tree[folder];
|
||||
api[verb](url)
|
||||
.query(({ path, page }) => {
|
||||
if (path !== folder) {
|
||||
return false;
|
||||
}
|
||||
if (expectedPage && page && parseInt(page, 10) !== parseInt(expectedPage, 10)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.times(repeat)
|
||||
.reply(uri => {
|
||||
const { page = 1, per_page = 20 } = parseQuery(uri);
|
||||
const pageCount = tree.length <= per_page ? 1 : Math.round(tree.length / per_page);
|
||||
const pageLastIndex = page * per_page;
|
||||
const pageFirstIndex = pageLastIndex - per_page;
|
||||
const resp = tree.slice(pageFirstIndex, pageLastIndex);
|
||||
return [
|
||||
200,
|
||||
verb === 'head' ? null : resp,
|
||||
createHeaders(backend, {
|
||||
basePath: url,
|
||||
path: folder,
|
||||
page,
|
||||
perPage: per_page,
|
||||
pageCount,
|
||||
totalCount: tree.length,
|
||||
}),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
function interceptFiles(backend, path) {
|
||||
const api = mockApi(backend);
|
||||
const url = `${expectedRepoUrl}/repository/files/${encodeURIComponent(path)}/raw`;
|
||||
api.get(url).query(true).reply(200, mockRepo.files[path]);
|
||||
|
||||
api
|
||||
.get(`${expectedRepoUrl}/repository/commits`)
|
||||
.query(({ path }) => path === path)
|
||||
.reply(200, [
|
||||
{
|
||||
author_name: 'author_name',
|
||||
author_email: 'author_email',
|
||||
authored_date: 'authored_date',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
function sharedSetup() {
|
||||
beforeEach(async () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend);
|
||||
await backend.authenticate(mockCredentials);
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { verb: 'head' });
|
||||
interceptCollection(backend, collectionContentConfig, { verb: 'head' });
|
||||
});
|
||||
}
|
||||
|
||||
it('throws if configuration does not include repo', () => {
|
||||
expect(() => resolveBackend({ backend: {} })).toThrowErrorMatchingInlineSnapshot(
|
||||
`"The GitLab backend needs a \\"repo\\" in the backend configuration."`,
|
||||
);
|
||||
});
|
||||
|
||||
describe('authComponent', () => {
|
||||
it('returns authentication page component', () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
expect(backend.authComponent()).toEqual(AuthenticationPage);
|
||||
});
|
||||
});
|
||||
|
||||
describe('authenticate', () => {
|
||||
it('throws if user does not have access to project', async () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend, { projectResponse: resp.project.readOnly });
|
||||
await expect(
|
||||
backend.authenticate(mockCredentials),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Your GitLab user account does not have access to this repo."`,
|
||||
);
|
||||
});
|
||||
|
||||
it('stores and returns user object on success', async () => {
|
||||
const backendName = defaultConfig.backend.name;
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend);
|
||||
const user = await backend.authenticate(mockCredentials);
|
||||
expect(authStore.retrieve()).toEqual(user);
|
||||
expect(user).toEqual({ ...resp.user.success, ...mockCredentials, backendName });
|
||||
});
|
||||
});
|
||||
|
||||
describe('currentUser', () => {
|
||||
it('returns null if no user', async () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
const user = await backend.currentUser();
|
||||
expect(user).toEqual(null);
|
||||
});
|
||||
|
||||
it('returns the stored user if exists', async () => {
|
||||
const backendName = defaultConfig.backend.name;
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend);
|
||||
await backend.authenticate(mockCredentials);
|
||||
const user = await backend.currentUser();
|
||||
expect(user).toEqual({ ...resp.user.success, ...mockCredentials, backendName });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToken', () => {
|
||||
it('returns the token for the current user', async () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend);
|
||||
await backend.authenticate(mockCredentials);
|
||||
const token = await backend.getToken();
|
||||
expect(token).toEqual(mockCredentials.token);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout', () => {
|
||||
it('sets token to null', async () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
interceptAuth(backend);
|
||||
await backend.authenticate(mockCredentials);
|
||||
await backend.logout();
|
||||
const token = await backend.getToken();
|
||||
expect(token).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEntry', () => {
|
||||
sharedSetup();
|
||||
|
||||
it('returns an entry from folder collection', async () => {
|
||||
const entryTree = mockRepo.tree[collectionContentConfig.folder][0];
|
||||
const slug = entryTree.path.split('/').pop().replace('.md', '');
|
||||
|
||||
interceptFiles(backend, entryTree.path);
|
||||
interceptCollection(backend, collectionContentConfig);
|
||||
|
||||
const entry = await backend.getEntry(
|
||||
{
|
||||
config: {},
|
||||
integrations: fromJS([]),
|
||||
entryDraft: fromJS({}),
|
||||
mediaLibrary: fromJS({}),
|
||||
},
|
||||
fromJS(collectionContentConfig),
|
||||
slug,
|
||||
);
|
||||
|
||||
expect(entry).toEqual(expect.objectContaining({ path: entryTree.path }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('listEntries', () => {
|
||||
sharedSetup();
|
||||
|
||||
it('returns entries from folder collection', async () => {
|
||||
const tree = mockRepo.tree[collectionContentConfig.folder];
|
||||
tree.forEach(file => interceptFiles(backend, file.path));
|
||||
|
||||
interceptCollection(backend, collectionContentConfig);
|
||||
const entries = await backend.listEntries(fromJS(collectionContentConfig));
|
||||
|
||||
expect(entries).toEqual({
|
||||
cursor: expect.any(Cursor),
|
||||
pagination: 1,
|
||||
entries: expect.arrayContaining(
|
||||
tree.map(file => expect.objectContaining({ path: file.path })),
|
||||
),
|
||||
});
|
||||
expect(entries.entries).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('returns all entries from folder collection', async () => {
|
||||
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
|
||||
interceptBranch(backend);
|
||||
tree.forEach(file => interceptFiles(backend, file.path));
|
||||
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { repeat: 5 });
|
||||
const entries = await backend.listAllEntries(fromJS(collectionManyEntriesConfig));
|
||||
|
||||
expect(entries).toEqual(
|
||||
expect.arrayContaining(tree.map(file => expect.objectContaining({ path: file.path }))),
|
||||
);
|
||||
expect(entries).toHaveLength(500);
|
||||
}, 7000);
|
||||
|
||||
it('returns entries from file collection', async () => {
|
||||
const { files } = collectionFilesConfig;
|
||||
files.forEach(file => interceptFiles(backend, file.file));
|
||||
const entries = await backend.listEntries(fromJS(collectionFilesConfig));
|
||||
|
||||
expect(entries).toEqual({
|
||||
cursor: expect.any(Cursor),
|
||||
entries: expect.arrayContaining(
|
||||
files.map(file => expect.objectContaining({ path: file.file })),
|
||||
),
|
||||
});
|
||||
expect(entries.entries).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('returns first page from paginated folder collection tree', async () => {
|
||||
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
|
||||
const pageTree = tree.slice(0, 20);
|
||||
pageTree.forEach(file => interceptFiles(backend, file.path));
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { page: 1 });
|
||||
const entries = await backend.listEntries(fromJS(collectionManyEntriesConfig));
|
||||
|
||||
expect(entries.entries).toEqual(
|
||||
expect.arrayContaining(pageTree.map(file => expect.objectContaining({ path: file.path }))),
|
||||
);
|
||||
expect(entries.entries).toHaveLength(20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('traverseCursor', () => {
|
||||
sharedSetup();
|
||||
|
||||
it('returns complete last page of paginated tree', async () => {
|
||||
const tree = mockRepo.tree[collectionManyEntriesConfig.folder];
|
||||
tree.slice(0, 20).forEach(file => interceptFiles(backend, file.path));
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { page: 1 });
|
||||
const entries = await backend.listEntries(fromJS(collectionManyEntriesConfig));
|
||||
|
||||
const nextPageTree = tree.slice(20, 40);
|
||||
nextPageTree.forEach(file => interceptFiles(backend, file.path));
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { page: 2 });
|
||||
const nextPage = await backend.traverseCursor(entries.cursor, 'next');
|
||||
|
||||
expect(nextPage.entries).toEqual(
|
||||
expect.arrayContaining(
|
||||
nextPageTree.map(file => expect.objectContaining({ path: file.path })),
|
||||
),
|
||||
);
|
||||
expect(nextPage.entries).toHaveLength(20);
|
||||
|
||||
const lastPageTree = tree.slice(-20);
|
||||
lastPageTree.forEach(file => interceptFiles(backend, file.path));
|
||||
interceptCollection(backend, collectionManyEntriesConfig, { page: 25 });
|
||||
const lastPage = await backend.traverseCursor(nextPage.cursor, 'last');
|
||||
expect(lastPage.entries).toEqual(
|
||||
expect.arrayContaining(
|
||||
lastPageTree.map(file => expect.objectContaining({ path: file.path })),
|
||||
),
|
||||
);
|
||||
expect(lastPage.entries).toHaveLength(20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterFile', () => {
|
||||
it('should return true for nested file with matching depth', () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
|
||||
expect(
|
||||
backend.implementation.filterFile(
|
||||
'content/posts',
|
||||
{ name: 'index.md', path: 'content/posts/dir1/dir2/index.md' },
|
||||
'md',
|
||||
3,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for nested file with non matching depth', () => {
|
||||
backend = resolveBackend(defaultConfig);
|
||||
|
||||
expect(
|
||||
backend.implementation.filterFile(
|
||||
'content/posts',
|
||||
{ name: 'index.md', path: 'content/posts/dir1/dir2/index.md' },
|
||||
'md',
|
||||
2,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
authStore.logout();
|
||||
backend = null;
|
||||
expect(authStore.retrieve()).toEqual(null);
|
||||
});
|
||||
});
|
||||
470
node_modules/decap-cms-backend-gitlab/src/implementation.ts
generated
vendored
Normal file
470
node_modules/decap-cms-backend-gitlab/src/implementation.ts
generated
vendored
Normal file
@@ -0,0 +1,470 @@
|
||||
import trimStart from 'lodash/trimStart';
|
||||
import semaphore from 'semaphore';
|
||||
import { trim } from 'lodash';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import {
|
||||
CURSOR_COMPATIBILITY_SYMBOL,
|
||||
basename,
|
||||
entriesByFolder,
|
||||
entriesByFiles,
|
||||
getMediaDisplayURL,
|
||||
getMediaAsBlob,
|
||||
unpublishedEntries,
|
||||
getPreviewStatus,
|
||||
asyncLock,
|
||||
runWithLock,
|
||||
getBlobSHA,
|
||||
blobToFileObj,
|
||||
contentKeyFromBranch,
|
||||
generateContentKey,
|
||||
localForage,
|
||||
allEntriesByFolder,
|
||||
filterByExtension,
|
||||
branchFromContentKey,
|
||||
getDefaultBranchName,
|
||||
} from 'decap-cms-lib-util';
|
||||
|
||||
import AuthenticationPage from './AuthenticationPage';
|
||||
import API, { API_NAME } from './API';
|
||||
|
||||
import type {
|
||||
Entry,
|
||||
AssetProxy,
|
||||
PersistOptions,
|
||||
Cursor,
|
||||
Implementation,
|
||||
DisplayURL,
|
||||
User,
|
||||
Credentials,
|
||||
Config,
|
||||
ImplementationFile,
|
||||
UnpublishedEntryMediaFile,
|
||||
AsyncLock,
|
||||
} from 'decap-cms-lib-util';
|
||||
import type { Semaphore } from 'semaphore';
|
||||
|
||||
const MAX_CONCURRENT_DOWNLOADS = 10;
|
||||
|
||||
export default class GitLab implements Implementation {
|
||||
lock: AsyncLock;
|
||||
api: API | null;
|
||||
options: {
|
||||
proxied: boolean;
|
||||
API: API | null;
|
||||
initialWorkflowStatus: string;
|
||||
};
|
||||
repo: string;
|
||||
isBranchConfigured: boolean;
|
||||
branch: string;
|
||||
apiRoot: string;
|
||||
token: string | null;
|
||||
squashMerges: boolean;
|
||||
cmsLabelPrefix: string;
|
||||
mediaFolder: string;
|
||||
previewContext: string;
|
||||
useGraphQL: boolean;
|
||||
graphQLAPIRoot: string;
|
||||
|
||||
_mediaDisplayURLSem?: Semaphore;
|
||||
|
||||
constructor(config: Config, options = {}) {
|
||||
this.options = {
|
||||
proxied: false,
|
||||
API: null,
|
||||
initialWorkflowStatus: '',
|
||||
...options,
|
||||
};
|
||||
|
||||
if (
|
||||
!this.options.proxied &&
|
||||
(config.backend.repo === null || config.backend.repo === undefined)
|
||||
) {
|
||||
throw new Error('The GitLab backend needs a "repo" in the backend configuration.');
|
||||
}
|
||||
|
||||
this.api = this.options.API || null;
|
||||
|
||||
this.repo = config.backend.repo || '';
|
||||
this.branch = config.backend.branch || 'master';
|
||||
this.isBranchConfigured = config.backend.branch ? true : false;
|
||||
this.apiRoot = config.backend.api_root || 'https://gitlab.com/api/v4';
|
||||
this.token = '';
|
||||
this.squashMerges = config.backend.squash_merges || false;
|
||||
this.cmsLabelPrefix = config.backend.cms_label_prefix || '';
|
||||
this.mediaFolder = config.media_folder;
|
||||
this.previewContext = config.backend.preview_context || '';
|
||||
this.useGraphQL = config.backend.use_graphql || false;
|
||||
this.graphQLAPIRoot = config.backend.graphql_api_root || 'https://gitlab.com/api/graphql';
|
||||
this.lock = asyncLock();
|
||||
}
|
||||
|
||||
isGitBackend() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async status() {
|
||||
const auth =
|
||||
(await this.api
|
||||
?.user()
|
||||
.then(user => !!user)
|
||||
.catch(e => {
|
||||
console.warn('Failed getting GitLab user', e);
|
||||
return false;
|
||||
})) || false;
|
||||
|
||||
return { auth: { status: auth }, api: { status: true, statusPage: '' } };
|
||||
}
|
||||
|
||||
authComponent() {
|
||||
return AuthenticationPage;
|
||||
}
|
||||
|
||||
restoreUser(user: User) {
|
||||
return this.authenticate(user);
|
||||
}
|
||||
|
||||
async authenticate(state: Credentials) {
|
||||
this.token = state.token as string;
|
||||
this.api = new API({
|
||||
token: this.token,
|
||||
branch: this.branch,
|
||||
repo: this.repo,
|
||||
apiRoot: this.apiRoot,
|
||||
squashMerges: this.squashMerges,
|
||||
cmsLabelPrefix: this.cmsLabelPrefix,
|
||||
initialWorkflowStatus: this.options.initialWorkflowStatus,
|
||||
useGraphQL: this.useGraphQL,
|
||||
graphQLAPIRoot: this.graphQLAPIRoot,
|
||||
});
|
||||
const user = await this.api.user();
|
||||
const isCollab = await this.api.hasWriteAccess().catch((error: Error) => {
|
||||
error.message = stripIndent`
|
||||
Repo "${this.repo}" not found.
|
||||
|
||||
Please ensure the repo information is spelled correctly.
|
||||
|
||||
If the repo is private, make sure you're logged into a GitLab account with access.
|
||||
`;
|
||||
throw error;
|
||||
});
|
||||
|
||||
// Unauthorized user
|
||||
if (!isCollab) {
|
||||
throw new Error('Your GitLab user account does not have access to this repo.');
|
||||
}
|
||||
|
||||
if (!this.isBranchConfigured) {
|
||||
const defaultBranchName = await getDefaultBranchName({
|
||||
backend: 'gitlab',
|
||||
repo: this.repo,
|
||||
token: this.token,
|
||||
apiRoot: this.apiRoot,
|
||||
});
|
||||
if (defaultBranchName) {
|
||||
this.branch = defaultBranchName;
|
||||
}
|
||||
}
|
||||
// Authorized user
|
||||
return { ...user, login: user.username, token: state.token as string };
|
||||
}
|
||||
|
||||
async logout() {
|
||||
this.token = null;
|
||||
return;
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return Promise.resolve(this.token);
|
||||
}
|
||||
|
||||
filterFile(
|
||||
folder: string,
|
||||
file: { path: string; name: string },
|
||||
extension: string,
|
||||
depth: number,
|
||||
) {
|
||||
// gitlab paths include the root folder
|
||||
const fileFolder = trim(file.path.split(folder)[1] || '/', '/');
|
||||
return filterByExtension(file, extension) && fileFolder.split('/').length <= depth;
|
||||
}
|
||||
|
||||
async entriesByFolder(folder: string, extension: string, depth: number) {
|
||||
let cursor: Cursor;
|
||||
|
||||
const listFiles = () =>
|
||||
this.api!.listFiles(folder, depth > 1).then(({ files, cursor: c }) => {
|
||||
cursor = c.mergeMeta({ folder, extension, depth });
|
||||
return files.filter(file => this.filterFile(folder, file, extension, depth));
|
||||
});
|
||||
|
||||
const files = await entriesByFolder(
|
||||
listFiles,
|
||||
this.api!.readFile.bind(this.api!),
|
||||
this.api!.readFileMetadata.bind(this.api),
|
||||
API_NAME,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
files[CURSOR_COMPATIBILITY_SYMBOL] = cursor;
|
||||
return files;
|
||||
}
|
||||
|
||||
async listAllFiles(folder: string, extension: string, depth: number) {
|
||||
const files = await this.api!.listAllFiles(folder, depth > 1);
|
||||
const filtered = files.filter(file => this.filterFile(folder, file, extension, depth));
|
||||
return filtered;
|
||||
}
|
||||
|
||||
async allEntriesByFolder(folder: string, extension: string, depth: number) {
|
||||
const files = await allEntriesByFolder({
|
||||
listAllFiles: () => this.listAllFiles(folder, extension, depth),
|
||||
readFile: this.api!.readFile.bind(this.api!),
|
||||
readFileMetadata: this.api!.readFileMetadata.bind(this.api),
|
||||
apiName: API_NAME,
|
||||
branch: this.branch,
|
||||
localForage,
|
||||
folder,
|
||||
extension,
|
||||
depth,
|
||||
getDefaultBranch: () =>
|
||||
this.api!.getDefaultBranch().then(b => ({ name: b.name, sha: b.commit.id })),
|
||||
isShaExistsInBranch: this.api!.isShaExistsInBranch.bind(this.api!),
|
||||
getDifferences: (to, from) => this.api!.getDifferences(to, from),
|
||||
getFileId: path => this.api!.getFileId(path, this.branch),
|
||||
filterFile: file => this.filterFile(folder, file, extension, depth),
|
||||
customFetch: this.useGraphQL ? files => this.api!.readFilesGraphQL(files) : undefined,
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
entriesByFiles(files: ImplementationFile[]) {
|
||||
return entriesByFiles(
|
||||
files,
|
||||
this.api!.readFile.bind(this.api!),
|
||||
this.api!.readFileMetadata.bind(this.api),
|
||||
API_NAME,
|
||||
);
|
||||
}
|
||||
|
||||
// Fetches a single entry.
|
||||
getEntry(path: string) {
|
||||
return this.api!.readFile(path).then(data => ({
|
||||
file: { path, id: null },
|
||||
data: data as string,
|
||||
}));
|
||||
}
|
||||
|
||||
getMedia(mediaFolder = this.mediaFolder) {
|
||||
return this.api!.listAllFiles(mediaFolder).then(files =>
|
||||
files.map(({ id, name, path }) => {
|
||||
return { id, name, path, displayURL: { id, name, path } };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
getMediaDisplayURL(displayURL: DisplayURL) {
|
||||
this._mediaDisplayURLSem = this._mediaDisplayURLSem || semaphore(MAX_CONCURRENT_DOWNLOADS);
|
||||
return getMediaDisplayURL(
|
||||
displayURL,
|
||||
this.api!.readFile.bind(this.api!),
|
||||
this._mediaDisplayURLSem,
|
||||
);
|
||||
}
|
||||
|
||||
async getMediaFile(path: string) {
|
||||
const name = basename(path);
|
||||
const blob = await getMediaAsBlob(path, null, this.api!.readFile.bind(this.api!));
|
||||
const fileObj = blobToFileObj(name, blob);
|
||||
const url = URL.createObjectURL(fileObj);
|
||||
const id = await getBlobSHA(blob);
|
||||
|
||||
return {
|
||||
id,
|
||||
displayURL: url,
|
||||
path,
|
||||
name,
|
||||
size: fileObj.size,
|
||||
file: fileObj,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
async persistEntry(entry: Entry, options: PersistOptions) {
|
||||
// persistEntry is a transactional operation
|
||||
return runWithLock(
|
||||
this.lock,
|
||||
() => this.api!.persistFiles(entry.dataFiles, entry.assets, options),
|
||||
'Failed to acquire persist entry lock',
|
||||
);
|
||||
}
|
||||
|
||||
async persistMedia(mediaFile: AssetProxy, options: PersistOptions) {
|
||||
const fileObj = mediaFile.fileObj as File;
|
||||
|
||||
const [id] = await Promise.all([
|
||||
getBlobSHA(fileObj),
|
||||
this.api!.persistFiles([], [mediaFile], options),
|
||||
]);
|
||||
|
||||
const { path } = mediaFile;
|
||||
const url = URL.createObjectURL(fileObj);
|
||||
|
||||
return {
|
||||
displayURL: url,
|
||||
path: trimStart(path, '/'),
|
||||
name: fileObj!.name,
|
||||
size: fileObj!.size,
|
||||
file: fileObj,
|
||||
url,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
deleteFiles(paths: string[], commitMessage: string) {
|
||||
return this.api!.deleteFiles(paths, commitMessage);
|
||||
}
|
||||
|
||||
traverseCursor(cursor: Cursor, action: string) {
|
||||
return this.api!.traverseCursor(cursor, action).then(async ({ entries, cursor: newCursor }) => {
|
||||
const [folder, depth, extension] = [
|
||||
cursor.meta?.get('folder') as string,
|
||||
cursor.meta?.get('depth') as number,
|
||||
cursor.meta?.get('extension') as string,
|
||||
];
|
||||
if (folder && depth && extension) {
|
||||
entries = entries.filter(f => this.filterFile(folder, f, extension, depth));
|
||||
newCursor = newCursor.mergeMeta({ folder, extension, depth });
|
||||
}
|
||||
const entriesWithData = await entriesByFiles(
|
||||
entries,
|
||||
this.api!.readFile.bind(this.api!),
|
||||
this.api!.readFileMetadata.bind(this.api)!,
|
||||
API_NAME,
|
||||
);
|
||||
return {
|
||||
entries: entriesWithData,
|
||||
cursor: newCursor,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
loadMediaFile(branch: string, file: UnpublishedEntryMediaFile) {
|
||||
const readFile = (
|
||||
path: string,
|
||||
id: string | null | undefined,
|
||||
{ parseText }: { parseText: boolean },
|
||||
) => this.api!.readFile(path, id, { branch, parseText });
|
||||
|
||||
return getMediaAsBlob(file.path, null, readFile).then(blob => {
|
||||
const name = basename(file.path);
|
||||
const fileObj = blobToFileObj(name, blob);
|
||||
return {
|
||||
id: file.path,
|
||||
displayURL: URL.createObjectURL(fileObj),
|
||||
path: file.path,
|
||||
name,
|
||||
size: fileObj.size,
|
||||
file: fileObj,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async loadEntryMediaFiles(branch: string, files: UnpublishedEntryMediaFile[]) {
|
||||
const mediaFiles = await Promise.all(files.map(file => this.loadMediaFile(branch, file)));
|
||||
|
||||
return mediaFiles;
|
||||
}
|
||||
|
||||
async unpublishedEntries() {
|
||||
const listEntriesKeys = () =>
|
||||
this.api!.listUnpublishedBranches().then(branches =>
|
||||
branches.map(branch => contentKeyFromBranch(branch)),
|
||||
);
|
||||
|
||||
const ids = await unpublishedEntries(listEntriesKeys);
|
||||
return ids;
|
||||
}
|
||||
|
||||
async unpublishedEntry({
|
||||
id,
|
||||
collection,
|
||||
slug,
|
||||
}: {
|
||||
id?: string;
|
||||
collection?: string;
|
||||
slug?: string;
|
||||
}) {
|
||||
if (id) {
|
||||
const data = await this.api!.retrieveUnpublishedEntryData(id);
|
||||
return data;
|
||||
} else if (collection && slug) {
|
||||
const entryId = generateContentKey(collection, slug);
|
||||
const data = await this.api!.retrieveUnpublishedEntryData(entryId);
|
||||
return data;
|
||||
} else {
|
||||
throw new Error('Missing unpublished entry id or collection and slug');
|
||||
}
|
||||
}
|
||||
|
||||
getBranch(collection: string, slug: string) {
|
||||
const contentKey = generateContentKey(collection, slug);
|
||||
const branch = branchFromContentKey(contentKey);
|
||||
return branch;
|
||||
}
|
||||
|
||||
async unpublishedEntryDataFile(collection: string, slug: string, path: string, id: string) {
|
||||
const branch = this.getBranch(collection, slug);
|
||||
const data = (await this.api!.readFile(path, id, { branch })) as string;
|
||||
return data;
|
||||
}
|
||||
|
||||
async unpublishedEntryMediaFile(collection: string, slug: string, path: string, id: string) {
|
||||
const branch = this.getBranch(collection, slug);
|
||||
const mediaFile = await this.loadMediaFile(branch, { path, id });
|
||||
return mediaFile;
|
||||
}
|
||||
|
||||
async updateUnpublishedEntryStatus(collection: string, slug: string, newStatus: string) {
|
||||
// updateUnpublishedEntryStatus is a transactional operation
|
||||
return runWithLock(
|
||||
this.lock,
|
||||
() => this.api!.updateUnpublishedEntryStatus(collection, slug, newStatus),
|
||||
'Failed to acquire update entry status lock',
|
||||
);
|
||||
}
|
||||
|
||||
async deleteUnpublishedEntry(collection: string, slug: string) {
|
||||
// deleteUnpublishedEntry is a transactional operation
|
||||
return runWithLock(
|
||||
this.lock,
|
||||
() => this.api!.deleteUnpublishedEntry(collection, slug),
|
||||
'Failed to acquire delete entry lock',
|
||||
);
|
||||
}
|
||||
|
||||
async publishUnpublishedEntry(collection: string, slug: string) {
|
||||
// publishUnpublishedEntry is a transactional operation
|
||||
return runWithLock(
|
||||
this.lock,
|
||||
() => this.api!.publishUnpublishedEntry(collection, slug),
|
||||
'Failed to acquire publish entry lock',
|
||||
);
|
||||
}
|
||||
|
||||
async getDeployPreview(collection: string, slug: string) {
|
||||
try {
|
||||
const statuses = await this.api!.getStatuses(collection, slug);
|
||||
const deployStatus = getPreviewStatus(statuses, this.previewContext);
|
||||
|
||||
if (deployStatus) {
|
||||
const { target_url: url, state } = deployStatus;
|
||||
return { url, status: state };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
node_modules/decap-cms-backend-gitlab/src/index.ts
generated
vendored
Normal file
10
node_modules/decap-cms-backend-gitlab/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import GitLabBackend from './implementation';
|
||||
import API from './API';
|
||||
import AuthenticationPage from './AuthenticationPage';
|
||||
|
||||
export const DecapCmsBackendGitlab = {
|
||||
GitLabBackend,
|
||||
API,
|
||||
AuthenticationPage,
|
||||
};
|
||||
export { GitLabBackend, API, AuthenticationPage };
|
||||
73
node_modules/decap-cms-backend-gitlab/src/queries.ts
generated
vendored
Normal file
73
node_modules/decap-cms-backend-gitlab/src/queries.ts
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import { gql } from 'graphql-tag';
|
||||
import { oneLine } from 'common-tags';
|
||||
|
||||
export const files = gql`
|
||||
query files($repo: ID!, $branch: String!, $path: String!, $recursive: Boolean!, $cursor: String) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
tree(ref: $branch, path: $path, recursive: $recursive) {
|
||||
blobs(after: $cursor) {
|
||||
nodes {
|
||||
type
|
||||
id: sha
|
||||
path
|
||||
name
|
||||
}
|
||||
pageInfo {
|
||||
endCursor
|
||||
hasNextPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const blobs = gql`
|
||||
query blobs($repo: ID!, $branch: String!, $paths: [String!]!) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
blobs(ref: $branch, paths: $paths) {
|
||||
nodes {
|
||||
id
|
||||
data: rawBlob
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function lastCommits(paths: string[]) {
|
||||
const tree = paths
|
||||
.map(
|
||||
(path, index) => oneLine`
|
||||
tree${index}: tree(ref: $branch, path: "${path}") {
|
||||
lastCommit {
|
||||
authorName
|
||||
authoredDate
|
||||
author {
|
||||
id
|
||||
username
|
||||
name
|
||||
publicEmail
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
)
|
||||
.join('\n');
|
||||
|
||||
const query = gql`
|
||||
query lastCommits($repo: ID!, $branch: String!) {
|
||||
project(fullPath: $repo) {
|
||||
repository {
|
||||
${tree}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return query;
|
||||
}
|
||||
3
node_modules/decap-cms-backend-gitlab/webpack.config.js
generated
vendored
Normal file
3
node_modules/decap-cms-backend-gitlab/webpack.config.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
const { getConfig } = require('../../scripts/webpack.js');
|
||||
|
||||
module.exports = getConfig();
|
||||
Reference in New Issue
Block a user