Skip to content
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

wiby clean #81

Merged
merged 10 commits into from
Feb 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
# Usage


## `wiby clean`



Use this command to clean up branches created by wiby (i.e. branches with the
"wiby-" prefix).

```
Options:

--dependent URL of a dependent [string]
--config Path to the configuration file. By default it will try to load
the configuration from the first file it finds in the current
working directory: `.wiby.json`, `.wiby.js` [string]
--all Remove all branches with "wiby-" prefix. By default, `wiby clean`
will only remove the branch that would be created if `wiby test`
ran in the current repository, on the current branch.
--dry-run Print the list of branches to be removed.
```


## `wiby result`


Expand Down
30 changes: 30 additions & 0 deletions bin/commands/clean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'

const wiby = require('../..')

exports.desc = 'Use this command to clean up branches created by wiby (i.e. branches with the "wiby-" prefix).'

exports.builder = (yargs) => yargs
.option('dependent', {
desc: 'URL of a dependent',
type: 'string',
conflicts: 'config'
})
.option('config', {
desc: 'Path to the configuration file. By default it will try to load the configuration from the first file it finds in the current working directory: `.wiby.json`, `.wiby.js`',
type: 'string'
})
.option('all', {
desc: 'Remove all branches with "wiby-" prefix. By default, `wiby clean` will only remove the branch that would be created if `wiby test` ran in the current repository, on the current branch.'
})
.option('dry-run', {
desc: 'Print the list of branches to be removed.'
})

exports.handler = async (params) => {
const config = params.dependent
? { dependents: [{ repository: params.dependent }] }
: wiby.validate({ config: params.config })

return wiby.clean(config, params)
}
2 changes: 2 additions & 0 deletions bin/generate-usage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env node

'use strict'

/**
* Builds new content for USAGE.md page according to wiby --help commands list
*/
Expand Down
7 changes: 7 additions & 0 deletions bin/wiby
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/usr/bin/env node

'use strict'

process.on('unhandledRejection', (err) => {

throw err;
});

require('dotenv').config()

const chalk = require('chalk')
Expand Down
44 changes: 44 additions & 0 deletions lib/clean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict'

const github = require('./github')
const gitURLParse = require('git-url-parse')
const logger = require('./logger')

// setup logger namespace
const cleanCommandNamespace = 'wiby:clean'
const debug = logger(cleanCommandNamespace)

module.exports = async ({ dependents }, { all, dryRun }) => {
// enable log output for clean command without DEBUG env
logger.enableLogs(cleanCommandNamespace)

const parentPkgJSON = await require('./test').getLocalPackageJSON()
const parentPkgInfo = gitURLParse(parentPkgJSON.repository.url)
debug(`Parent module: ${parentPkgInfo.owner}/${parentPkgJSON.name}`)

console.log(dryRun ? 'Branches to be deleted:' : 'Branches deleted:')

for (const { repository: url } of dependents) {
const dependentPkgInfo = gitURLParse(url)

let branches

const branch = await require('./result').getBranchName(parentPkgJSON.name)

if (all) {
branches = await github.getWibyBranches(dependentPkgInfo.owner, dependentPkgInfo.name)
} else if (await github.getBranch(dependentPkgInfo.owner, dependentPkgInfo.name, branch)) {
branches = [branch]
} else {
branches = []
}

if (!dryRun) {
for (const branch of branches) {
await github.deleteBranch(dependentPkgInfo.owner, dependentPkgInfo.name, branch)
}
}

console.log(`- ${dependentPkgInfo}: ${branches.length ? branches.join(', ') : '(none)'}`)
}
}
48 changes: 39 additions & 9 deletions lib/github.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
'use strict'

const { graphql } = require('@octokit/graphql')
const { Octokit } = require('@octokit/rest')

const queries = require('./graphql')

const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
})
Expand All @@ -13,15 +18,7 @@ const graphqlWithAuth = graphql.defaults({
module.exports.getPackageJson = async function getPackageJson (owner, repo) {
try {
const resp = await graphqlWithAuth({
query: `query($owner: String!, $repo: String!) {
repository(name: $repo, owner: $owner) {
object(expression: "HEAD:package.json") {
... on Blob {
text
}
}
}
}`,
query: queries.getPackageJson,
owner: owner,
repo: repo
})
Expand All @@ -35,6 +32,16 @@ module.exports.getPackageJson = async function getPackageJson (owner, repo) {
}
}

module.exports.getWibyBranches = async function (owner, repo) {
const resp = await graphqlWithAuth({
query: queries.getWibyBranches,
owner: owner,
repo: repo
})
const edges = resp.organization.repository.refs.edges
return edges.map(({ node: { branchName } }) => branchName)
}

module.exports.getShas = async function getShas (owner, repo) {
const resp = await octokit.repos.listCommits({
owner,
Expand Down Expand Up @@ -91,6 +98,29 @@ module.exports.createBranch = async function createBranch (owner, repo, commitSh
})
}

module.exports.deleteBranch = async function deleteBranch (owner, repo, branch) {
await octokit.git.deleteRef({
owner,
repo,
ref: `heads/${branch}`
})
}

module.exports.getBranch = async function getBranch (owner, repo, branch) {
try {
return await octokit.repos.getBranch({
owner,
repo,
branch
})
} catch (err) {
if (err.status === 404) {
return undefined
}
throw err
}
}

module.exports.getChecks = async function getChecks (owner, repo, branch) {
return octokit.checks.listForRef({
owner,
Expand Down
9 changes: 9 additions & 0 deletions lib/graphql/getPackageJson.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
query($owner: String!, $repo: String!) {
repository(name: $repo, owner: $owner) {
object(expression: "HEAD:package.json") {
... on Blob {
text
}
}
}
}
18 changes: 18 additions & 0 deletions lib/graphql/getWibyBranches.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
query getExistingRepoBranches($owner: String!, $repo: String!) {
organization(login: $owner) {
repository(name: $repo) {
id
name
refs(refPrefix: "refs/heads/", query: "wiby-", first: 100) {
edges {
node {
branchName: name
}
}
pageInfo {
endCursor
}
}
}
}
}
8 changes: 8 additions & 0 deletions lib/graphql/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict'

const fs = require('fs')
const path = require('path')

exports.getPackageJson = fs.readFileSync(path.join(__dirname, 'getPackageJson.graphql')).toString()

exports.getWibyBranches = fs.readFileSync(path.join(__dirname, 'getWibyBranches.graphql')).toString()
2 changes: 2 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

exports.clean = require('./clean')

exports.test = require('./test')

exports.result = require('./result')
Expand Down
2 changes: 2 additions & 0 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const debugPkg = require('debug')

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/result.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const test = require('./test')
const github = require('./github')
const gitURLParse = require('git-url-parse')
Expand Down
2 changes: 2 additions & 0 deletions lib/test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const fsPromises = require('fs').promises
const github = require('./github')
const gitURLParse = require('git-url-parse')
Expand Down
38 changes: 38 additions & 0 deletions test/clean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict'

require('dotenv').config()
const tap = require('tap')
const nock = require('nock')
const CONFIG = require('./fixtures/config')
const wiby = require('..')

tap.beforeEach(async () => {
nock.disableNetConnect()
})

tap.afterEach(async () => {
nock.cleanAll()
nock.enableNetConnect()
})

tap.test('wiby.clean()', async (tap) => {
tap.test('should check if the wiby branch exists', async (tap) => {
nock('https://api.github.com')
.get(`/repos/wiby-test/${CONFIG.DEP_REPO}/branches/wiby-wiby`)
.reply(404)

await wiby.clean({ dependents: [{ repository: `https://www.github.com/${CONFIG.DEP_ORG}/${CONFIG.DEP_REPO}` }] }, {})
rodion-arr marked this conversation as resolved.
Show resolved Hide resolved

// implied assertion - no DELETE requests expected - we don't need to delete the missing `wiby-wiby` branch
})

tap.test('should rethrow when github API inaccessible during branch check', async (tap) => {
nock('https://api.github.com')
.get(`/repos/wiby-test/${CONFIG.DEP_REPO}/branches/wiby-wiby`)
.reply(500)

await tap.rejects(
wiby.clean({ dependents: [{ repository: `https://www.github.com/${CONFIG.DEP_ORG}/${CONFIG.DEP_REPO}` }] }, {})
)
})
})
69 changes: 63 additions & 6 deletions test/cli.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const tap = require('tap')
const childProcess = require('child_process')
const path = require('path')
Expand Down Expand Up @@ -26,7 +28,7 @@ tap.test('test command', async (tap) => {
}
}).toString()

tap.equal(true, result.includes('Changes pushed to https://github.com/wiby-test/fakeRepo/blob/wiby-wiby/package.json'))
tap.includes(result, 'Changes pushed to https://github.com/wiby-test/fakeRepo/blob/wiby-wiby/package.json')
})

tap.test('test command should call test module with all deps from .wiby.json', async (tap) => {
Expand All @@ -37,9 +39,9 @@ tap.test('test command', async (tap) => {
}
}).toString()

tap.equal(true, result.includes('Changes pushed to https://github.com/wiby-test/pass/blob/wiby-wiby/package.json'))
tap.equal(true, result.includes('Changes pushed to https://github.com/wiby-test/fail/blob/wiby-wiby/package.json'))
tap.equal(true, result.includes('Changes pushed to https://github.com/wiby-test/partial/blob/wiby-wiby/package.json'))
tap.includes(result, 'Changes pushed to https://github.com/wiby-test/pass/blob/wiby-wiby/package.json')
tap.includes(result, 'Changes pushed to https://github.com/wiby-test/fail/blob/wiby-wiby/package.json')
tap.includes(result, 'Changes pushed to https://github.com/wiby-test/partial/blob/wiby-wiby/package.json')
})
})

Expand Down Expand Up @@ -146,8 +148,63 @@ tap.test('result command', async (tap) => {

tap.test('validate command', async (tap) => {
tap.test('should pass on wiby itself', async (tap) => {
const result = childProcess.execSync(`${wibyCommand} validate`, { cwd: cwd }).toString()
console.info(result)
childProcess.execSync(`${wibyCommand} validate`, { cwd: cwd })
tap.end()
})
})

tap.test('clean command', async (tap) => {
tap.test('should delete test branch in all configured test modules', async (tap) => {
const result = childProcess.execSync(`${wibyCommand} clean`, {
cwd: cwd,
env: {
NODE_OPTIONS: '-r ./test/fixtures/http/clean-command.js'
}
}).toString()

tap.includes(result, 'Branches deleted:')
tap.includes(result, '- https://github.com/wiby-test/partial: wiby-wiby')
tap.includes(result, '- git://github.com/wiby-test/fail: wiby-wiby')
tap.includes(result, '- git+https://github.com/wiby-test/pass: wiby-wiby')
})

tap.test('should delete test branch in the test module at dependent URI', async (tap) => {
const result = childProcess.execSync(`${wibyCommand} clean --dependent="https://github.com/wiby-test/fakeRepo"`, {
cwd: cwd,
env: {
NODE_OPTIONS: '-r ./test/fixtures/http/clean-command.js'
}
}).toString()

tap.includes(result, 'Branches deleted:')
tap.includes(result, '- https://github.com/wiby-test/fakeRepo: wiby-wiby')
})

tap.test('should delete all wiby-* branches in all configured test modules', async (tap) => {
const result = childProcess.execSync(`${wibyCommand} clean --all`, {
cwd: cwd,
env: {
NODE_OPTIONS: '-r ./test/fixtures/http/clean-command-all.js'
}
}).toString()

tap.includes(result, 'Branches deleted:')
tap.includes(result, '- https://github.com/wiby-test/partial: wiby-partial-one, wiby-partial-two')
tap.includes(result, '- git://github.com/wiby-test/fail: wiby-fail-one, wiby-fail-two')
tap.includes(result, '- git+https://github.com/wiby-test/pass: wiby-pass-one, wiby-pass-two')
})

tap.test('should not delete during dry-run', async (tap) => {
const result = childProcess.execSync(`${wibyCommand} clean --dry-run`, {
cwd: cwd,
env: {
NODE_OPTIONS: '-r ./test/fixtures/http/clean-command-dry.js'
}
}).toString()

tap.includes(result, 'Branches to be deleted:')
tap.includes(result, '- https://github.com/wiby-test/partial: wiby-wiby')
tap.includes(result, '- git://github.com/wiby-test/fail: wiby-wiby')
tap.includes(result, '- git+https://github.com/wiby-test/pass: wiby-wiby')
})
})
Loading