-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(backend-github): prepend collection name #2878
Changes from 5 commits
b1e8a58
0c04316
232de41
93b9b75
73e7ef5
19a650f
7f32f8e
6bc1071
32c5e99
8bbd5d6
c448609
24cd1d5
6b534e4
eca36df
7ae7e52
2a9a3bd
24ccfd9
3910cea
f7ce7b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ import { | |
APIError, | ||
EditorialWorkflowError, | ||
filterPromisesWith, | ||
flowAsync, | ||
localForage, | ||
onlySuccessfulPromises, | ||
resolvePromiseProperties, | ||
|
@@ -148,9 +149,7 @@ export default class API { | |
|
||
generateContentKey(collectionName, slug) { | ||
if (!this.useOpenAuthoring) { | ||
// this doesn't use the collection, but we need to leave it that way for backwards | ||
// compatibility | ||
return slug; | ||
return `${collectionName}/${slug}`; | ||
} | ||
|
||
return `${this.repo}/${collectionName}/${slug}`; | ||
|
@@ -225,6 +224,29 @@ export default class API { | |
); | ||
} | ||
|
||
deleteMetadata(key) { | ||
if (!this._metadataSemaphore) { | ||
this._metadataSemaphore = semaphore(1); | ||
} | ||
return new Promise(resolve => | ||
this._metadataSemaphore.take(async () => { | ||
try { | ||
const branchData = await this.checkMetadataRef(); | ||
const file = { path: `${key}.json`, sha: null }; | ||
|
||
const changeTree = await this.updateTree(branchData.sha, [file]); | ||
const { sha } = await this.commit(`Deleting “${key}” metadata`, changeTree); | ||
await this.patchRef('meta', '_netlify_cms', sha); | ||
this._metadataSemaphore.leave(); | ||
resolve(); | ||
} catch (err) { | ||
this._metadataSemaphore.leave(); | ||
resolve(); | ||
} | ||
}), | ||
); | ||
} | ||
|
||
retrieveMetadata(key) { | ||
const cache = localForage.getItem(`gh.meta.${key}`); | ||
return cache.then(cached => { | ||
|
@@ -394,27 +416,21 @@ export default class API { | |
}); | ||
} | ||
|
||
getPRsForBranchName = ({ | ||
branchName, | ||
state, | ||
base = this.branch, | ||
repoURL = this.repoURL, | ||
usernameOfFork, | ||
} = {}) => { | ||
getPRsForBranchName = branchName => { | ||
// Get PRs with a `head` of `branchName`. Note that this is a | ||
// substring match, so we need to check that the `head.ref` of | ||
// at least one of the returned objects matches `branchName`. | ||
return this.requestAllPages(`${repoURL}/pulls`, { | ||
return this.requestAllPages(`${this.repoURL}/pulls`, { | ||
params: { | ||
head: usernameOfFork ? `${usernameOfFork}:${branchName}` : branchName, | ||
...(state ? { state } : {}), | ||
base, | ||
head: branchName, | ||
state: 'open', | ||
base: this.branch, | ||
}, | ||
}); | ||
}; | ||
|
||
branchHasPR = async ({ branchName, ...rest }) => { | ||
const prs = await this.getPRsForBranchName({ branchName, ...rest }); | ||
branchHasPR = async branchName => { | ||
const prs = await this.getPRsForBranchName(branchName); | ||
return prs.some(pr => pr.head.ref === branchName); | ||
}; | ||
|
||
|
@@ -459,14 +475,55 @@ export default class API { | |
return metadata; | ||
}; | ||
|
||
async migrateToVersion1(oldContentKey, metaData) { | ||
const newContentKey = this.generateContentKey(metaData.collection, oldContentKey); | ||
const newBranchName = this.generateBranchName(newContentKey); | ||
|
||
// create new branch and pull request in new format | ||
const newBranch = await this.createBranch(newBranchName, metaData.pr.head); | ||
const pr = await this.createPR(metaData.commitMessage, newBranchName); | ||
|
||
// store new metadata | ||
await this.storeMetadata(newContentKey, { | ||
...metaData, | ||
pr: { | ||
number: pr.number, | ||
head: pr.head.sha, | ||
}, | ||
branch: newBranchName, | ||
version: '1', | ||
}); | ||
|
||
// remove old data | ||
await this.closePR(metaData.pr); | ||
await this.deleteBranch(metaData.branch); | ||
await this.deleteMetadata(oldContentKey); | ||
|
||
return newBranch; | ||
} | ||
|
||
async migrateBranch(branch) { | ||
const contentKey = this.contentKeyFromRef(branch.ref); | ||
const metadata = await this.retrieveMetadata(contentKey); | ||
if (!metadata.version) { | ||
// migrate branch from cms/slug to cms/collection/slug | ||
branch = await this.migrateToVersion1(contentKey, metadata); | ||
} | ||
|
||
return branch; | ||
} | ||
|
||
async listUnpublishedBranches() { | ||
console.log( | ||
'%c Checking for Unpublished entries', | ||
'line-height: 30px;text-align: center;font-weight: bold', | ||
); | ||
const onlyBranchesWithOpenPRs = filterPromisesWith(({ ref }) => | ||
this.branchHasPR({ branchName: this.branchNameFromRef(ref), state: 'open' }), | ||
); | ||
const onlyBranchesWithOpenPRs = flowAsync([ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Used a new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see here: Instead of sending a |
||
filterPromisesWith(({ ref }) => this.branchHasPR(this.branchNameFromRef(ref))), | ||
map(branch => this.migrateBranch(branch)), | ||
onlySuccessfulPromises, | ||
]); | ||
|
||
const getUpdatedOpenAuthoringBranches = flow([ | ||
map(async branch => { | ||
const contentKey = this.contentKeyFromRef(branch.ref); | ||
|
@@ -621,6 +678,7 @@ export default class API { | |
files: mediaFilesList, | ||
}, | ||
timeStamp: new Date().toISOString(), | ||
version: '1', | ||
}); | ||
} else { | ||
// Entry is already on editorial review workflow - just update metadata and commit to existing branch | ||
|
@@ -862,6 +920,7 @@ export default class API { | |
this.retrieveMetadata(contentKey) | ||
.then(metadata => (metadata && metadata.pr ? this.closePR(metadata.pr) : Promise.resolve())) | ||
.then(() => this.deleteBranch(branchName)) | ||
.then(() => this.deleteMetadata(contentKey)) | ||
// If the PR doesn't exist, then this has already been deleted - | ||
// deletion should be idempotent, so we can consider this a | ||
// success. | ||
|
@@ -881,6 +940,7 @@ export default class API { | |
const metadata = await this.retrieveMetadata(contentKey); | ||
await this.mergePR(metadata.pr, metadata.objects); | ||
await this.deleteBranch(branchName); | ||
await this.deleteMetadata(contentKey); | ||
|
||
return metadata; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -387,8 +387,8 @@ export default class GitHub { | |
const promises = []; | ||
branches.map(({ ref }) => { | ||
promises.push( | ||
new Promise(resolve => { | ||
const contentKey = ref.split('refs/heads/cms/').pop(); | ||
new Promise(async resolve => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I forgot to remove that. |
||
const contentKey = this.api.contentKeyFromRef(ref); | ||
const slug = contentKey.split('/').pop(); | ||
return sem.take(() => | ||
this.api | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!