Skip to content

Commit

Permalink
feat: handle greenkeeper.json changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Realtin authored and hulkoba committed Mar 26, 2018
1 parent f880eb3 commit f427ee5
Show file tree
Hide file tree
Showing 8 changed files with 1,751 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function (doc) {
if (doc.type !== 'branch' || doc.referenceDeleted) return
if (doc.head && typeof doc.head === 'string') {
var branchName = doc.head.split('/')
if (branchName[1]) {
emit([doc.repositoryId, branchName[1]])
}
}
}
File renamed without changes.
98 changes: 67 additions & 31 deletions jobs/github-event/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ const env = require('../../lib/env')
const { updateRepoDoc } = require('../../lib/repository-docs')
const updatedAt = require('../../lib/updated-at')
const diff = require('../../lib/diff-package-json')
const diffGreenkeeperJson = require('../../lib/diff-greenkeeper-json')
const deleteBranches = require('../../lib/delete-branches')
const { maybeUpdatePaymentsJob } = require('../../lib/payments')
const { getBranchesToDelete } = require('../../lib/branches-to-delete')
const {
getDependencyBranchesToDelete,
getGroupBranchesToDelete
} = require('../../lib/branches-to-delete')
const getConfig = require('../../lib/get-config')

module.exports = async function (data) {
Expand Down Expand Up @@ -53,7 +57,8 @@ module.exports = async function (data) {
}
}

if (_.isEqual(oldPkg, pkg)) {
// check if there are changes in packag.json files or the greenkeeper config
if (_.isEqual(oldPkg, pkg) && _.isEqual(config, repoDoc.greenkeeper)) {
await updateDoc(repositories, repository, repoDoc)
return null
}
Expand All @@ -78,42 +83,55 @@ module.exports = async function (data) {
// do diff + getBranchesToDelete per file for each group

// TODO: for Tuesday -> deleting a package.json needs to be detected!!
const branches = []
Object.keys(pkg).forEach((path) => {
let groupName = null
if (config.groups) {
Object.keys(config.groups).map((group) => {
if (config.groups[group].packages.includes(path)) {
groupName = group
}
})
}
const changes = diff(oldPkg[path], pkg[path], groupName)
branches.push(getBranchesToDelete(changes))
})

/*
const changes = diff(oldPkg, pkg)
console.log('changes', changes)
const branches = await getDependencyBranchesForAllGroups({pkg, oldPkg, config, repositories, repositoryId})
const configChanges = diffGreenkeeperJson(config, repoDoc.greenkeeper)
console.log('configChanges', configChanges)
console.log('dependencyChanges', branches)

const branches = getBranchesToDelete(changes)
*/
// console.log('branches to be deleted!!', branches)
// do this per group, if groups, else once

// MONDAY CONTINUE HERE

// TODO: config includes no groups
// console.log('config', config)
const groupBranchesToDelete = await getGroupBranchesToDelete({configChanges, repositories, repositoryId})
console.log('branches in push', branches)
const allBranchesToDelete = branches.concat(groupBranchesToDelete)
const _branches = _.uniqWith(_.flattenDeep(allBranchesToDelete), _.isEqual)
console.log('allBranchesToDelete flattend&uniq', _branches)

await Promise.mapSeries(
_.uniqWith(_.flatten(branches), _.isEqual),
_branches,
deleteBranches.bind(null, {
installationId: installation.id,
fullName: repository.full_name,
repositoryId
})
)

if (configChanges.added.length || configChanges.modified.length) {
const relevantModifiedGroups = configChanges.modified.filter((group) => {
if (!_.isEmpty(_.difference(repoDoc.greenkeeper.groups[group].packages, config.groups[group].packages))) {
return true
}
})
console.log('relevantModifiedGroups', relevantModifiedGroups)
const groupsToRecvieveInitialBranch = configChanges.added.concat(relevantModifiedGroups)
console.log('groupsToRecvieveInitialBranch', groupsToRecvieveInitialBranch)
if (_.isEmpty(groupsToRecvieveInitialBranch)) return
// create subgroup initial pr
return _(groupsToRecvieveInitialBranch)
.map(groupName => ({
data: {
name: 'create-initial-subgroup-branch',
repositoryId,
accountId: repoDoc.accountId,
groupName
}
}))
.value()
}

// do this per group, if groups, else once

// MONDAY CONTINUE HERE

// TODO: config includes no groups
// console.log('config', config)
}

function updateDoc (repositories, repository, repoDoc) {
Expand All @@ -129,8 +147,6 @@ function updateDoc (repositories, repository, repoDoc) {
)
}

// check for relevant files in all folders!
// TODO: currently we might just detect those files in the root directory
function hasRelevantChanges (commits, files) {
return _.some(files, file => {
return _.some(['added', 'removed', 'modified'], changeType => {
Expand All @@ -151,3 +167,23 @@ async function disableRepo ({ repositories, repoDoc, repository }) {
return maybeUpdatePaymentsJob(repoDoc.accountId, repoDoc.private)
}
}

async function getDependencyBranchesForAllGroups ({pkg, oldPkg, config, repositories, repositoryId}) {
return Promise.all(Object.keys(pkg).map(async (path) => {
let groupName = null
if (config.groups) {
Object.keys(config.groups).map((group) => {
if (config.groups[group].packages.includes(path)) {
groupName = group
}
})
}
// this can only happen if a package.json was modified
const dependencyDiff = diff(oldPkg[path], pkg[path], groupName)
console.log('dependencyDiff', dependencyDiff)
if (!_.isEmpty(dependencyDiff)) {
return getDependencyBranchesToDelete({changes: dependencyDiff, repositories, repositoryId})
}
return []
}))
}
87 changes: 79 additions & 8 deletions lib/branches-to-delete.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
const _ = require('lodash')
const semver = require('semver')

function getBranchesToDelete (changes) {
let branches = []
module.exports = {
getDependencyChanges,
getDependencyBranchesToDelete,
getGroupBranchesToDelete
}

function getDependencyChanges (changes) {
console.log('changes in getDependencyChanges', changes)
let dependencyChanges = []

_.each(changes, (type, dependencyType) => {
_.each(type, (dep, dependency) => {
console.log('dep', dep)
console.log('dep.change === added', dep.change === 'added')
if (dep.change === 'added') return
branches.push(
dependencyChanges.push(
Object.assign(
{
dependency,
Expand All @@ -20,9 +26,74 @@ function getBranchesToDelete (changes) {
})
})

return branches
return dependencyChanges
}
async function getDependencyBranchesToDelete ({changes, repositories, repositoryId}) {
const dependencyChanges = getDependencyChanges(changes)

module.exports = {
getBranchesToDelete
return Promise.all(dependencyChanges.map(async dependencyChange => {
return getSingleDependencyBranchesToDelete({changes: dependencyChange, repositories, repositoryId})
}))
}

async function getSingleDependencyBranchesToDelete ({changes, repositories, repositoryId}) {
console.log('changes in getSingleDependencyBranchesToDelete', changes)
const { change, after, dependency, dependencyType, groupName } = changes

let branches = []
if (change !== 'removed' && !semver.validRange(after)) return []

// TODO: this would return multiple branch docs, possibly for irrelevant groups,
// or if a group is specified, for irrelevant root level package.json
branches = _.map(
(await repositories.query('branch_by_dependency', {
key: [repositoryId, dependency, dependencyType],
include_docs: true
})).rows,
'doc'
)
console.log('branches in getSingleDependencyBranchesToDelete', branches)
return _(branches)
.filter(
branch =>
// include branch if dependency was removed
change === 'removed' ||
// include branch if update version satisfies branch version (branch is outdated)
semver.satisfies(branch.version, after) ||
// include branch if is not satisfied, but later (eg. update is an out of range major update)
semver.ltr(branch.version, after)
)
.filter(
branch => {
// if groupName is passed in, only include branches of that group
// branch.head = 'greenkeeper/${groupName}/${dependency}'
if (groupName) {
console.log('has groupName', groupName)
return branch.head.includes(`greenkeeper/${groupName}/`)
} else {
// If there's no groupName, only return branches that don’t belong to groups
return branch.head.includes(`greenkeeper/${dependency}`)
}
})
.value()
}

async function getGroupBranchesToDelete ({configChanges, repositories, repositoryId}) {
if (configChanges.removed.length || configChanges.modified.length) {
const groups = _.uniq(configChanges.removed.concat(configChanges.modified))
// delete all branches for those groups
console.log('groups', groups)
return Promise.all(_.map(groups, async (group) => {
console.log('map über group', group)
return Promise.all(_.map(
(await repositories.query('branch_by_group', {
key: [repositoryId, group],
include_docs: true
})).rows,
'doc'
))
}))
} else {
return []
}
}
70 changes: 15 additions & 55 deletions lib/delete-branches.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,26 @@
const _ = require('lodash')
const semver = require('semver')

const dbs = require('../lib/dbs')
const updatedAt = require('../lib/updated-at')
const githubQueue = require('./github-queue')

module.exports = async function (
{ installationId, fullName, repositoryId },
{ change, after, dependency, dependencyType, groupName }
branch
) {
if (change !== 'removed' && !semver.validRange(after)) return
const { repositories } = await dbs()

const [owner, repo] = fullName.split('/')
console.log('branch to be deleted', branch)
if (!branch) return
let referenceDeleted = false
try {
// TODO: check if modified
await githubQueue(installationId).write(github => github.gitdata.deleteReference({
owner,
repo,
ref: `heads/${branch.head}`
}))
referenceDeleted = true
} catch (e) {}
updatedAt(Object.assign(branch, { referenceDeleted }))

// TODO: this would return multiple branch docs, possibly for irrelevant groups,
// or if a group is specified, for irrelevant root level package.json
const branches = _.map(
(await repositories.query('branch_by_dependency', {
key: [repositoryId, dependency, dependencyType],
include_docs: true
})).rows,
'doc'
)

const branchDocs = await Promise.all(
_(branches)
.filter(
branch =>
// include branch if dependency was removed
change === 'removed' ||
// include branch if update version satisfies branch version (branch is outdated)
semver.satisfies(branch.version, after) ||
// include branch if is not satisfied, but later (eg. update is an out of range major update)
semver.ltr(branch.version, after)
)
.filter(
branch => {
// if groupName is passed in, only include branches of that group
// branch.head = 'greenkeeper/${groupName}/${dependency}'
if (groupName) {
return branch.head.includes(`greenkeeper/${groupName}/`)
} else {
// If there's no groupName, only return branches that don’t belong to groups
return branch.head.includes(`greenkeeper/${dependency}`)
}
})
.map(async branch => {
let referenceDeleted = false
try {
// TODO: check if modified
await githubQueue(installationId).write(github => github.gitdata.deleteReference({
owner,
repo,
ref: `heads/${branch.head}`
}))
referenceDeleted = true
} catch (e) {}
return updatedAt(Object.assign(branch, { referenceDeleted }))
})
.value()
)

return repositories.bulkDocs(branchDocs)
return repositories.bulkDocs([branch])
}
16 changes: 16 additions & 0 deletions lib/diff-greenkeeper-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const _ = require('lodash')

module.exports = function (oldFile, newFile) {
const changes = {added: [], removed: [], modified: []}
if (!newFile || !oldFile) return changes
// new groups added
_.set(changes, 'added', _.difference(_.keys(newFile.groups), _.keys(oldFile.groups)))
// groups removed
_.set(changes, 'removed', _.difference(_.keys(oldFile.groups), _.keys(newFile.groups)))
// groups modified
_.set(changes, 'modified', _.compact(_.map(oldFile.groups, (group, key) => {
if (newFile.groups[key] && !_.isEqual(group.packages, newFile.groups[key].packages)) return key
})))

return changes
}
Loading

0 comments on commit f427ee5

Please sign in to comment.