migrate GitLab backend
This commit is contained in:
parent
33f490055d
commit
faab1e38ba
@ -15,7 +15,7 @@ export default class API {
|
|||||||
this.repoURL = `/repos/${ this.repo }`;
|
this.repoURL = `/repos/${ this.repo }`;
|
||||||
this.merge_method = config.squash_merges ? "squash" : "merge";
|
this.merge_method = config.squash_merges ? "squash" : "merge";
|
||||||
this.initialStatus = config.initialStatus;
|
this.initialStatus = config.initialStatus;
|
||||||
|
this.useWorkflow = config.useWorkflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
user() {
|
user() {
|
||||||
|
@ -2,39 +2,13 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import styled from 'react-emotion';
|
import styled from 'react-emotion';
|
||||||
import { NetlifyAuthenticator } from 'netlify-cms-lib-auth';
|
import { NetlifyAuthenticator } from 'netlify-cms-lib-auth';
|
||||||
import { Icon, buttons, shadows } from 'netlify-cms-ui-default';
|
import { AuthenticationPage, Icon, buttons, shadows } from 'netlify-cms-ui-default';
|
||||||
|
|
||||||
const StyledAuthenticationPage = styled.section`
|
const LoginButtonIcon = styled(Icon)`
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100vh;
|
|
||||||
`
|
|
||||||
|
|
||||||
const PageLogoIcon = styled(Icon)`
|
|
||||||
color: #c4c6d2;
|
|
||||||
margin-top: -300px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const LoginButton = styled.button`
|
|
||||||
${buttons.button};
|
|
||||||
${shadows.dropDeep};
|
|
||||||
${buttons.default};
|
|
||||||
${buttons.gray};
|
|
||||||
|
|
||||||
padding: 0 12px;
|
|
||||||
margin-top: -40px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
${Icon} {
|
|
||||||
margin-right: 18px;
|
margin-right: 18px;
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
export default class AuthenticationPage extends React.Component {
|
export default class GitHubAuthenticationPage extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onLogin: PropTypes.func.isRequired,
|
onLogin: PropTypes.func.isRequired,
|
||||||
inProgress: PropTypes.bool,
|
inProgress: PropTypes.bool,
|
||||||
@ -64,17 +38,18 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loginError } = this.state;
|
|
||||||
const { inProgress } = this.props;
|
const { inProgress } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledAuthenticationPage>
|
<AuthenticationPage
|
||||||
<PageLogoIcon size="300px" type="netlify-cms"/>
|
onLogin={this.handleLogin}
|
||||||
{loginError ? <p>{loginError}</p> : null}
|
loginDisabled={inProgress}
|
||||||
<LoginButton disabled={inProgress} onClick={this.handleLogin}>
|
loginErrorMessage={this.state.loginError}
|
||||||
<Icon type="github" /> {inProgress ? "Logging in..." : "Login with GitHub"}
|
renderButtonContent={() => (
|
||||||
</LoginButton>
|
<React.Fragment>
|
||||||
</StyledAuthenticationPage>
|
<LoginButtonIcon type="github"/> {inProgress ? "Logging in..." : "Login with GitHub"}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,14 @@ export default class GitHub {
|
|||||||
|
|
||||||
authenticate(state) {
|
authenticate(state) {
|
||||||
this.token = state.token;
|
this.token = state.token;
|
||||||
this.api = new API({ token: this.token, branch: this.branch, repo: this.repo, api_root: this.api_root, squash_merges: this.squash_merges });
|
this.api = new API({
|
||||||
|
token: this.token,
|
||||||
|
branch: this.branch,
|
||||||
|
repo: this.repo,
|
||||||
|
api_root: this.api_root,
|
||||||
|
squash_merges: this.squash_merges,
|
||||||
|
useWorkflow: this.options.useWorkflow,
|
||||||
|
});
|
||||||
return this.api.user().then(user =>
|
return this.api.user().then(user =>
|
||||||
this.api.hasWriteAccess().then((isCollab) => {
|
this.api.hasWriteAccess().then((isCollab) => {
|
||||||
// Unauthorized user
|
// Unauthorized user
|
||||||
|
3
packages/netlify-cms-backend-gitlab/babel.config.js
Normal file
3
packages/netlify-cms-backend-gitlab/babel.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const config = require('../../babel.config.js');
|
||||||
|
|
||||||
|
module.exports = config;
|
41
packages/netlify-cms-backend-gitlab/package.json
Normal file
41
packages/netlify-cms-backend-gitlab/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "netlify-cms-backend-gitlab",
|
||||||
|
"description": "GitLab backend for Netlify CMS",
|
||||||
|
"version": "2.0.0-alpha.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "dist/netlify-cms-backend-gitlab.js",
|
||||||
|
"keywords": [
|
||||||
|
"netlify",
|
||||||
|
"netlify-cms",
|
||||||
|
"backend",
|
||||||
|
"gitlab"
|
||||||
|
],
|
||||||
|
"sideEffects": false,
|
||||||
|
"scripts": {
|
||||||
|
"watch": "webpack -w",
|
||||||
|
"build": "cross-env NODE_ENV=production webpack"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"js-base64": "^2.4.8",
|
||||||
|
"semaphore": "^1.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.0.0-beta.54",
|
||||||
|
"@babel/core": "^7.0.0-beta.54",
|
||||||
|
"cross-env": "^5.2.0",
|
||||||
|
"rollup": "^0.63.2",
|
||||||
|
"rollup-plugin-babel": "^4.0.0-beta.7",
|
||||||
|
"webpack": "^4.16.1",
|
||||||
|
"webpack-cli": "^3.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"immutable": "^3.7.6",
|
||||||
|
"lodash": "^4.17.10",
|
||||||
|
"netlify-cms-lib-auth": "2.0.0-alpha.0",
|
||||||
|
"netlify-cms-lib-util": "2.0.0-alpha.0",
|
||||||
|
"netlify-cms-ui-default": "2.0.0-alpha.0",
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
|
"react": "^16.4.1",
|
||||||
|
"react-emotion": "^9.2.6"
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ import { localForage, unsentRequest, then, APIError, Cursor } from "netlify-cms-
|
|||||||
import { Base64 } from "js-base64";
|
import { Base64 } from "js-base64";
|
||||||
import { fromJS, List, Map } from "immutable";
|
import { fromJS, List, Map } from "immutable";
|
||||||
import { cond, flow, isString, partial, partialRight, pick, omit, set, update, get } from "lodash";
|
import { cond, flow, isString, partial, partialRight, pick, omit, set, update, get } from "lodash";
|
||||||
import AssetProxy from "ValueObjects/AssetProxy";
|
|
||||||
|
|
||||||
export default class API {
|
export default class API {
|
||||||
constructor(config) {
|
constructor(config) {
|
@ -1,9 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'react-emotion';
|
||||||
import { NetlifyAuthenticator, ImplicitAuthenticator } from 'netlify-cms-lib-auth';
|
import { NetlifyAuthenticator, ImplicitAuthenticator } from 'netlify-cms-lib-auth';
|
||||||
import { Icon } from 'netlify-cms-ui-default';
|
import { AuthenticationPage, Icon, buttons, shadows } from 'netlify-cms-ui-default';
|
||||||
|
|
||||||
export default class AuthenticationPage extends React.Component {
|
const LoginButtonIcon = styled(Icon)`
|
||||||
|
margin-right: 18px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default class GitLabAuthenticationPage extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onLogin: PropTypes.func.isRequired,
|
onLogin: PropTypes.func.isRequired,
|
||||||
inProgress: PropTypes.bool,
|
inProgress: PropTypes.bool,
|
||||||
@ -49,21 +54,18 @@ export default class AuthenticationPage extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loginError } = this.state;
|
|
||||||
const { inProgress } = this.props;
|
const { inProgress } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="nc-githubAuthenticationPage-root">
|
<AuthenticationPage
|
||||||
<Icon className="nc-githubAuthenticationPage-logo" size="500px" type="netlify-cms"/>
|
onLogin={this.handleLogin}
|
||||||
{loginError && <p>{loginError}</p>}
|
loginDisabled={inProgress}
|
||||||
<button
|
loginErrorMessage={this.state.loginError}
|
||||||
className="nc-githubAuthenticationPage-button"
|
renderButtonContent={() => (
|
||||||
disabled={inProgress}
|
<React.Fragment>
|
||||||
onClick={this.handleLogin}
|
<LoginButtonIcon type="gitlab"/> {inProgress ? "Logging in..." : "Login with GitLab"}
|
||||||
>
|
</React.Fragment>
|
||||||
<Icon type="gitlab" /> {inProgress ? "Logging in..." : "Login with GitLab"}
|
)}
|
||||||
</button>
|
/>
|
||||||
</section>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,12 +3,11 @@ import semaphore from "semaphore";
|
|||||||
import { fileExtension, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
|
import { fileExtension, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
|
||||||
import AuthenticationPage from "./AuthenticationPage";
|
import AuthenticationPage from "./AuthenticationPage";
|
||||||
import API from "./API";
|
import API from "./API";
|
||||||
import { EDITORIAL_WORKFLOW } from "Constants/publishModes";
|
|
||||||
|
|
||||||
const MAX_CONCURRENT_DOWNLOADS = 10;
|
const MAX_CONCURRENT_DOWNLOADS = 10;
|
||||||
|
|
||||||
export default class GitLab {
|
export default class GitLab {
|
||||||
constructor(config, options={}) {
|
constructor(config, options = {}) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.options = {
|
this.options = {
|
||||||
proxied: false,
|
proxied: false,
|
||||||
@ -16,7 +15,7 @@ export default class GitLab {
|
|||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.getIn(["publish_mode"]) === EDITORIAL_WORKFLOW) {
|
if (this.options.useWorkflow) {
|
||||||
throw new Error("The GitLab backend does not support the Editorial Workflow.")
|
throw new Error("The GitLab backend does not support the Editorial Workflow.")
|
||||||
}
|
}
|
||||||
|
|
4
packages/netlify-cms-backend-gitlab/src/index.js
Normal file
4
packages/netlify-cms-backend-gitlab/src/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export GitLabBackend from './implementation';
|
||||||
|
export API from './API';
|
||||||
|
export AuthenticationPage from './AuthenticationPage';
|
||||||
|
|
1
packages/netlify-cms-backend-gitlab/webpack.config.js
Normal file
1
packages/netlify-cms-backend-gitlab/webpack.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('../../webpack.config.js');
|
@ -43,10 +43,11 @@ const getFolderEntries = (folder, extension) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class TestRepo {
|
export default class TestRepo {
|
||||||
constructor(config) {
|
constructor(config, options = {}) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.assets = [];
|
this.assets = [];
|
||||||
this.initialStatus = config.initialStatus;
|
this.initialStatus = config.initialStatus;
|
||||||
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
authComponent() {
|
authComponent() {
|
||||||
@ -135,7 +136,7 @@ export default class TestRepo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
persistEntry({ path, raw, slug }, mediaFiles = [], options = {}) {
|
persistEntry({ path, raw, slug }, mediaFiles = [], options = {}) {
|
||||||
if (options.useWorkflow) {
|
if (this.options.useWorkflow) {
|
||||||
const unpubStore = window.repoFilesUnpublished;
|
const unpubStore = window.repoFilesUnpublished;
|
||||||
const existingEntryIndex = unpubStore.findIndex(e => e.file.path === path);
|
const existingEntryIndex = unpubStore.findIndex(e => e.file.path === path);
|
||||||
if (existingEntryIndex >= 0) {
|
if (existingEntryIndex >= 0) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
backend:
|
backend:
|
||||||
name: test-repo
|
name: gitlab
|
||||||
|
repo: erquhart/blank
|
||||||
|
|
||||||
display_url: https://example.com
|
display_url: https://example.com
|
||||||
media_folder: "assets/uploads"
|
media_folder: "assets/uploads"
|
||||||
|
|
||||||
publish_mode: editorial_workflow # optional, enables publishing workflow
|
|
||||||
|
|
||||||
collections: # A list of collections the CMS should be able to edit
|
collections: # A list of collections the CMS should be able to edit
|
||||||
- name: "posts" # Used in routes, ie.: /admin/collections/:slug/edit
|
- name: "posts" # Used in routes, ie.: /admin/collections/:slug/edit
|
||||||
|
@ -2,6 +2,7 @@ import { attempt, flatten, isError } from 'lodash';
|
|||||||
import { fromJS, Map } from 'immutable';
|
import { fromJS, Map } from 'immutable';
|
||||||
import fuzzy from 'fuzzy';
|
import fuzzy from 'fuzzy';
|
||||||
import { GitHubBackend } from "netlify-cms-backend-github";
|
import { GitHubBackend } from "netlify-cms-backend-github";
|
||||||
|
import { GitLabBackend } from "netlify-cms-backend-gitlab";
|
||||||
import { TestBackend } from "netlify-cms-backend-test";
|
import { TestBackend } from "netlify-cms-backend-test";
|
||||||
import { resolveFormat } from "Formats/formats";
|
import { resolveFormat } from "Formats/formats";
|
||||||
import { selectIntegration } from 'Reducers/integrations';
|
import { selectIntegration } from 'Reducers/integrations';
|
||||||
@ -17,7 +18,6 @@ import {
|
|||||||
} from "Reducers/collections";
|
} from "Reducers/collections";
|
||||||
import { createEntry } from "ValueObjects/Entry";
|
import { createEntry } from "ValueObjects/Entry";
|
||||||
import { sanitizeSlug } from "Lib/urlHelper";
|
import { sanitizeSlug } from "Lib/urlHelper";
|
||||||
import GitLabBackend from "./gitlab/implementation";
|
|
||||||
import BitBucketBackend from "./bitbucket/implementation";
|
import BitBucketBackend from "./bitbucket/implementation";
|
||||||
import GitGatewayBackend from "./git-gateway/implementation";
|
import GitGatewayBackend from "./git-gateway/implementation";
|
||||||
import { registerBackend, getBackend } from 'Lib/registry';
|
import { registerBackend, getBackend } from 'Lib/registry';
|
||||||
@ -127,8 +127,11 @@ const sortByScore = (a, b) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Backend {
|
class Backend {
|
||||||
constructor(implementation, { authStore = null, backendName, config } = {}) {
|
constructor(implementation, { backendName, authStore = null, config } = {}) {
|
||||||
this.implementation = implementation.init(config, { updateUserCredentials: this.updateUserCredentials });
|
this.implementation = implementation.init(config, {
|
||||||
|
useWorkflow: config.getIn(["publish_mode"]) === EDITORIAL_WORKFLOW,
|
||||||
|
updateUserCredentials: this.updateUserCredentials,
|
||||||
|
});
|
||||||
this.backendName = backendName;
|
this.backendName = backendName;
|
||||||
this.authStore = authStore;
|
this.authStore = authStore;
|
||||||
if (this.implementation === null) {
|
if (this.implementation === null) {
|
||||||
@ -396,8 +399,6 @@ class Backend {
|
|||||||
|
|
||||||
const commitMessage = commitMessageFormatter(newEntry ? 'create' : 'update', config, { collection, slug: entryObj.slug, path: entryObj.path });
|
const commitMessage = commitMessageFormatter(newEntry ? 'create' : 'update', config, { collection, slug: entryObj.slug, path: entryObj.path });
|
||||||
|
|
||||||
const useWorkflow = config.get("publish_mode") === EDITORIAL_WORKFLOW;
|
|
||||||
|
|
||||||
const collectionName = collection.get("name");
|
const collectionName = collection.get("name");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -410,7 +411,6 @@ class Backend {
|
|||||||
parsedData,
|
parsedData,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
collectionName,
|
collectionName,
|
||||||
useWorkflow,
|
|
||||||
initialStatus: status.first(),
|
initialStatus: status.first(),
|
||||||
...updatedOptions
|
...updatedOptions
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { flow } from "lodash";
|
import { flow } from "lodash";
|
||||||
|
import { API as GitlabAPI } from "netlify-cms-backend-gitlab";
|
||||||
import { unsentRequest, then } from "netlify-cms-lib-util";
|
import { unsentRequest, then } from "netlify-cms-lib-util";
|
||||||
import GitlabAPI from "Backends/gitlab/API";
|
|
||||||
|
|
||||||
export default class API extends GitlabAPI {
|
export default class API extends GitlabAPI {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
@ -4,7 +4,7 @@ import {List} from 'immutable';
|
|||||||
import { get, pick, intersection } from "lodash";
|
import { get, pick, intersection } from "lodash";
|
||||||
import { unsentRequest } from "netlify-cms-lib-util";
|
import { unsentRequest } from "netlify-cms-lib-util";
|
||||||
import { GitHubBackend } from "netlify-cms-backend-github";
|
import { GitHubBackend } from "netlify-cms-backend-github";
|
||||||
import GitLabBackend from "Backends/gitlab/implementation";
|
import { GitLabBackend } from "netlify-cms-backend-gitlab";
|
||||||
import BitBucketBackend from "Backends/bitbucket/implementation";
|
import BitBucketBackend from "Backends/bitbucket/implementation";
|
||||||
import GitHubAPI from "./GitHubAPI";
|
import GitHubAPI from "./GitHubAPI";
|
||||||
import GitLabAPI from "./GitLabAPI";
|
import GitLabAPI from "./GitLabAPI";
|
||||||
|
43
packages/netlify-cms-ui-default/src/AuthenticationPage.js
Normal file
43
packages/netlify-cms-ui-default/src/AuthenticationPage.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'react-emotion';
|
||||||
|
import Icon from './Icon';
|
||||||
|
import { buttons, shadows } from './styles';
|
||||||
|
|
||||||
|
const StyledAuthenticationPage = styled.section`
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
`
|
||||||
|
|
||||||
|
const PageLogoIcon = styled(Icon)`
|
||||||
|
color: #c4c6d2;
|
||||||
|
margin-top: -300px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const LoginButton = styled.button`
|
||||||
|
${buttons.button};
|
||||||
|
${shadows.dropDeep};
|
||||||
|
${buttons.default};
|
||||||
|
${buttons.gray};
|
||||||
|
|
||||||
|
padding: 0 12px;
|
||||||
|
margin-top: -40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
`
|
||||||
|
|
||||||
|
const AuthenticationPage = ({ onLogin, loginDisabled, loginErrorMessage, renderButtonContent }) => (
|
||||||
|
<StyledAuthenticationPage>
|
||||||
|
<PageLogoIcon size="300px" type="netlify-cms"/>
|
||||||
|
{loginErrorMessage ? <p>{loginErrorMessage}</p> : null}
|
||||||
|
<LoginButton disabled={loginDisabled} onClick={onLogin}>
|
||||||
|
{renderButtonContent()}
|
||||||
|
</LoginButton>
|
||||||
|
</StyledAuthenticationPage>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AuthenticationPage;
|
@ -3,6 +3,7 @@ export Icon from './Icon';
|
|||||||
export ListItemTopBar from './ListItemTopBar';
|
export ListItemTopBar from './ListItemTopBar';
|
||||||
export Loader from './Loader';
|
export Loader from './Loader';
|
||||||
export Toggle from './Toggle';
|
export Toggle from './Toggle';
|
||||||
|
export AuthenticationPage from './AuthenticationPage';
|
||||||
export {
|
export {
|
||||||
fonts,
|
fonts,
|
||||||
colorsRaw,
|
colorsRaw,
|
||||||
|
@ -29,7 +29,7 @@ module.exports = {
|
|||||||
target: 'web',
|
target: 'web',
|
||||||
externals: (context, request, cb) => {
|
externals: (context, request, cb) => {
|
||||||
const peerDeps = Object.keys(pkg.peerDependencies || {});
|
const peerDeps = Object.keys(pkg.peerDependencies || {});
|
||||||
const isPeerDep = dep => new RegExp(`^${dep}/?`).test(request);
|
const isPeerDep = dep => new RegExp(`^${dep}($|/)`).test(request);
|
||||||
return peerDeps.some(isPeerDep) ? cb(null, request) : cb();
|
return peerDeps.some(isPeerDep) ? cb(null, request) : cb();
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user