Commiting unpublished branches on pre existing branch (updates PR)

This commit is contained in:
Cássio Zen 2016-09-13 14:31:18 -03:00
parent e8fe7e0c80
commit 686dd51410
4 changed files with 124 additions and 31 deletions

View File

@ -1,4 +1,5 @@
import { currentBackend } from '../backends/backend';
import { getMedia } from '../reducers';
import { EDITORIAL_WORKFLOW } from '../constants/publishModes';
/*
* Contant Declarations
@ -10,6 +11,8 @@ export const UNPUBLISHED_ENTRIES_REQUEST = 'UNPUBLISHED_ENTRIES_REQUEST';
export const UNPUBLISHED_ENTRIES_SUCCESS = 'UNPUBLISHED_ENTRIES_SUCCESS';
export const UNPUBLISHED_ENTRIES_FAILURE = 'UNPUBLISHED_ENTRIES_FAILURE';
export const UNPUBLISHED_ENTRY_PERSIST_REQUEST = 'UNPUBLISHED_ENTRY_PERSIST_REQUEST';
export const UNPUBLISHED_ENTRY_PERSIST_SUCCESS = 'UNPUBLISHED_ENTRY_PERSIST_SUCCESS';
/*
* Simple Action Creators (Internal)
@ -53,6 +56,28 @@ function unpublishedEntriesFailed(error) {
};
}
function unpublishedEntryPersisting(status, entry) {
return {
type: UNPUBLISHED_ENTRY_PERSIST_REQUEST,
payload: { status, entry }
};
}
function unpublishedEntryPersisted(status, entry) {
return {
type: UNPUBLISHED_ENTRY_PERSIST_SUCCESS,
payload: { status, entry }
};
}
function unpublishedEntryPersistedFail(status, entry) {
return {
type: UNPUBLISHED_ENTRY_PERSIST_SUCCESS,
payload: { status, entry }
};
}
/*
* Exported Thunk Action Creators
*/
@ -79,3 +104,18 @@ export function loadUnpublishedEntries() {
);
};
}
export function persistUnpublishedEntry(collection, status, entry) {
return (dispatch, getState) => {
const state = getState();
const backend = currentBackend(state.config);
const MediaProxies = entry && entry.get('mediaFiles').map(path => getMedia(state, path));
dispatch(unpublishedEntryPersisting(status, entry));
backend.persistUnpublishedEntry(state.config, collection, status, entry, MediaProxies.toJS()).then(
() => {
dispatch(unpublishedEntryPersisted(status, entry));
},
(error) => dispatch(unpublishedEntryPersistedFail(error))
);
};
}

View File

@ -105,7 +105,7 @@ class Backend {
});
}
persistEntry(config, collection, entryDraft, MediaFiles) {
persistEntry(config, collection, entryDraft, MediaFiles, options) {
const newEntry = entryDraft.getIn(['entry', 'newRecord']) || false;
const parsedData = {
@ -139,10 +139,15 @@ class Backend {
const collectionName = collection.get('name');
return this.implementation.persistEntry(entryObj, MediaFiles, {
newEntry, parsedData, commitMessage, collectionName, mode
newEntry, parsedData, commitMessage, collectionName, mode, ...options
});
}
persistUnpublishedEntry(config, collection, status, entryDraft, MediaFiles) {
return this.persistEntry(config, collection, entryDraft, MediaFiles, { unpublished: true, status });
}
entryToRaw(collection, entry) {
const format = resolveFormat(collection, entry);
return format && format.toFile(entry);

View File

@ -1,7 +1,8 @@
import LocalForage from 'localforage';
import MediaProxy from '../../valueObjects/MediaProxy';
import { Base64 } from 'js-base64';
import { EDITORIAL_WORKFLOW, status } from '../../constants/publishModes';
import _ from 'lodash';
import { SIMPLE, EDITORIAL_WORKFLOW, status } from '../../constants/publishModes';
const API_ROOT = 'https://api.github.com';
@ -183,37 +184,84 @@ export default class API {
subtree[filename] = file;
file.file = true;
});
return Promise.all(uploadPromises)
.then(() => this.getBranch())
return Promise.all(uploadPromises).then(() => {
if (!options.mode || (options.mode && options.mode === SIMPLE)) {
return this.getBranch()
.then(branchData => this.updateTree(branchData.commit.sha, '/', fileTree))
.then(changeTree => this.commit(options.commitMessage, changeTree))
.then(response => this.patchBranch(this.branch, response.sha));
} else if (options.mode && options.mode === EDITORIAL_WORKFLOW) {
const mediaFilesList = mediaFiles.map(file => file.path);
return this.editorialWorkflowGit(fileTree, entry, mediaFilesList, options);
}
});
}
editorialWorkflowGit(fileTree, entry, filesList, options) {
const contentKey = options.collectionName ? `${options.collectionName}-${entry.slug}` : entry.slug;
const branchName = `cms/${contentKey}`;
const unpublished = options.unpublished || false;
if (!unpublished) {
// Open new editorial review workflow for this entry - Create new metadata and commit to new branch
return this.getBranch()
.then(branchData => this.updateTree(branchData.commit.sha, '/', fileTree))
.then(changeTree => this.commit(options.commitMessage, changeTree))
.then((response) => {
if (options.mode && options.mode === EDITORIAL_WORKFLOW) {
const contentKey = options.collectionName ? `${options.collectionName}-${entry.slug}` : entry.slug;
const branchName = `cms/${contentKey}`;
return this.user().then(user => {
return user.name ? user.name : user.login;
})
.then(username => this.storeMetadata(contentKey, {
type: 'PR',
user: username,
status: status.first(),
branch: branchName,
collection: options.collectionName,
const contentKey = options.collectionName ? `${options.collectionName}-${entry.slug}` : entry.slug;
const branchName = `cms/${contentKey}`;
return this.user().then(user => {
return user.name ? user.name : user.login;
})
.then(username => this.storeMetadata(contentKey, {
type: 'PR',
user: username,
status: status.first(),
branch: branchName,
collection: options.collectionName,
title: options.parsedData && options.parsedData.title,
description: options.parsedData && options.parsedData.description,
objects: {
entry: entry.path,
files: filesList
},
timeStamp: new Date().toISOString()
}))
.then(this.createBranch(branchName, response.sha))
.then(this.createPR(options.commitMessage, `cms/${contentKey}`));
});
} else {
// Entry is already on editorial review workflow - just update metadata and commit to existing branch
return this.getBranch(branchName)
.then(branchData => this.updateTree(branchData.commit.sha, '/', fileTree))
.then(changeTree => this.commit(options.commitMessage, changeTree))
.then((response) => {
const contentKey = options.collectionName ? `${options.collectionName}-${entry.slug}` : entry.slug;
const branchName = `cms/${contentKey}`;
return this.user().then(user => {
return user.name ? user.name : user.login;
})
.then(username => this.retrieveMetadata(contentKey))
.then(metadata => {
let files = metadata.objects && metadata.objects.files || [];
files = files.concat(filesList);
return {
...metadata,
status: options.status,
title: options.parsedData && options.parsedData.title,
description: options.parsedData && options.parsedData.description,
objects: {
entry: entry.path,
files: mediaFiles.map(file => file.path)
files: _.uniq(files)
},
timeStamp: new Date().toISOString()
}))
.then(this.createBranch(branchName, response.sha))
.then(this.createPR(options.commitMessage, `cms/${contentKey}`));
} else {
return this.patchBranch(this.branch, response.sha);
}
};
})
.then(updatedMetadata => this.storeMetadata(contentKey, updatedMetadata))
.then(this.patchBranch(branchName, response.sha));
});
}
}
createRef(type, name, sha) {
@ -238,8 +286,8 @@ export default class API {
return this.patchRef('heads', branchName, sha);
}
getBranch() {
return this.request(`${this.repoURL}/branches/${this.branch}`);
getBranch(branch = this.branch) {
return this.request(`${this.repoURL}/branches/${branch}`);
}
createPR(title, head, base = 'master') {

View File

@ -1,7 +1,7 @@
import React from 'react';
import { EDITORIAL_WORKFLOW } from '../../constants/publishModes';
import { selectUnpublishedEntry } from '../../reducers';
import { loadUnpublishedEntry } from '../../actions/editorialWorkflow';
import { loadUnpublishedEntry, persistUnpublishedEntry } from '../../actions/editorialWorkflow';
import { connect } from 'react-redux';
export default function EntryPageHOC(EntryPage) {
@ -22,10 +22,6 @@ export default function EntryPageHOC(EntryPage) {
const slug = ownProps.params.slug;
const entry = selectUnpublishedEntry(state, status, slug);
returnObj.entry = entry;
returnObj.persistEntry = () => {
// TODO - for now, simply ignore
};
}
return returnObj;
}
@ -39,6 +35,10 @@ export default function EntryPageHOC(EntryPage) {
returnObj.loadEntry = (collection, slug) => {
dispatch(loadUnpublishedEntry(collection, status, slug));
};
returnObj.persistEntry = (collection, entryDraft) => {
dispatch(persistUnpublishedEntry(collection, status, entryDraft));
};
}
return returnObj;
}