Skip to content

Commit

Permalink
lib/test: add initial prototype for wiby --test
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewhughes101 committed Jun 3, 2020
1 parent 9692bfb commit a80429a
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 7 deletions.
20 changes: 17 additions & 3 deletions bin/wiby.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
#!/usr/bin/env node

require('dotenv').config()
const test = require('../lib/test')
const result = require('../lib/result')

if (process.argv[2] === 'test') {
test()
const args = require('yargs')
.option('test', {
alias: 't',
describe: 'Test your dependents'
})
.option('result', {
alias: 'r',
describe: 'Get the result of your tests'
})
.argv

if (args.test) {
test(args.test)
}

if (process.argv[2] === 'result') {
if (args.result) {
result()
}

// Usage: wiby --test URL
124 changes: 124 additions & 0 deletions lib/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
const { graphql } = require('@octokit/graphql')
const { Octokit } = require('@octokit/rest')
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN
})

const graphqlWithAuth = graphql.defaults({
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`
}
})

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: "master:package.json") {
... on Blob {
text
}
}
}
}`,
owner: owner,
repo: repo
})
return (JSON.parse(resp.repository.object.text))
} catch (err) {
if (err.errors && err.errors[0].type === 'NOT_FOUND') {
throw Error(`Could not find GitHub repository at https://www.github.com/${owner}/${repo}`)
} else {
throw err
}
}
}

module.exports.getPermissions =
async function getPermissions (owner, repo) {
try {
const resp = await graphqlWithAuth({
query: `query($owner: String!, $repo: String!) {
repository(name: $repo, owner: $owner) {
viewerPermission
}
}`,
owner: owner,
repo: repo
})
return resp.repository.viewerPermission
} catch (err) {
if (err.errors && err.errors[0].type === 'NOT_FOUND') {
throw Error(`Could not find GitHub repository at https://www.github.com/${owner}/${repo}`)
} else {
throw err
}
}
}

module.exports.getShas =
async function getShas (owner, repo) {
const resp = await octokit.repos.listCommits({
owner,
repo,
per_page: 1
})
const headSha = resp.data[0].sha
const treeSha = resp.data[0].commit.tree.sha
// console.log(`lastSha: ${headSha} treeSha: ${treeSha}`)
return [headSha, treeSha]
}

module.exports.createBlob =
async function createBlob (owner, repo, file) {
const {
data: { sha: blobSha }
} = await octokit.git.createBlob({
owner,
repo,
content: file,
encoding: 'base64'
})
return blobSha
}

module.exports.createTree = async function createTree (owner, repo, treeSha, blobSha) {
const resp = await octokit.git.createTree({
owner,
repo,
base_tree: treeSha,
tree: [
{ path: 'package.json', mode: '100644', sha: blobSha }
],
headers: {
Accept: 'application/json'
}
})
const newTreeSha = resp.data.sha
return newTreeSha
}

module.exports.createCommit =
async function createCommit (owner, repo, message, newTreeSha, headSha) {
const resp = await octokit.git.createCommit({
owner,
repo,
message: message,
tree: newTreeSha,
parents: [headSha]
})
const commitSha = resp.data.sha
return commitSha
}

module.exports.createBranch =
async function createBranch (owner, repo, commitSha, branch) {
await octokit.git.createRef({
owner,
repo,
sha: commitSha,
ref: `refs/heads/${branch}`
})
}
108 changes: 106 additions & 2 deletions lib/test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,107 @@
module.exports = () => {
console.log('wiby test')
const fs = require('fs')
const fetch = require('node-fetch')
const { promisify } = require('util')
const github = require('./github')
const readFileAsync = promisify(fs.readFile)

module.exports = async function (url) {
const dep = await getLocalPackageName()
console.log('Got local package name: ', dep)
const [org, repo] = getOrgRepo(url)
console.log(`Got org: ${org} and repo: ${repo}`)
const packageJSON = await github.getPackageJson(org, repo)
if (!checkPackageInPackageJSON(dep, packageJSON)) {
throw new Error('Dependency not found in package.json')
}
const patch = await getPatch(dep)
console.log('Created patch: ', patch)
const patchedPackageJSON = applyPatch(patch, dep, packageJSON)
await pushPatch(patchedPackageJSON, org, repo, dep)
}

const getCommitHash = module.exports.getCommitHash =
async function getCommitHash (owner, repo) {
const headSha = (await github.getShas(owner, repo))[0]
return headSha
}

const checkPackageInPackageJSON = module.exports.checkPackageInPackageJSON =
function checkPackageInPackageJSON (dep, packageJSON) {
return Object.prototype.hasOwnProperty.call(packageJSON.dependencies, dep)
}

const getOrgRepo = module.exports.getOrgRepo =
function getOrgRepo (url) {
const repoOrgArr = (url.split('github.com'))[1].split('/')
const org = repoOrgArr[1]
const repo = repoOrgArr[2]
return [org, repo]
}

const getPatch = module.exports.getPatch =
async function getPatch (dep, hash) {
dep = dep || await getLocalPackageName()
const [org, repo] = await getGitHubOrgRepo(dep)
hash = hash || await getCommitHash(org, repo)
const patch = `${org}/${repo}#${hash}`
return patch
}

const getLocalPackageName = module.exports.getLocalPackageName =
async function getLocalPackageName (pkgPath) {
pkgPath = pkgPath || 'package.json'
let pkg = await readFileAsync(pkgPath).catch((err) => {
throw (err)
})
pkg = JSON.parse(pkg)
return pkg.name
}

const getGitHubOrgRepo = module.exports.getGitHubOrgRepo =
async function getGitHubOrgRepo (dep) {
const urlRegex = /github.com\/([^/])+\/[^/]+/g
const resp = await fetchRegistryInfo(dep)
let org, repo
if (resp.repository && resp.repository.url) {
let gitUrl = (resp.repository.url).match(urlRegex)
if (gitUrl) {
gitUrl = gitUrl[0].replace(/(\.git)/g, '')
org = getOrgRepo(gitUrl)[0]
repo = getOrgRepo(gitUrl)[1]
}
}
if (!org && !repo) {
org = 'undefined'
repo = 'undefined'
}
return [org, repo]
}

const fetchRegistryInfo = module.exports.fetchRegistryInfo =
async function fetchRegistryInfo (dep) {
const resp = await fetch(`https://registry.npmjs.org/${dep}`)
return resp.json()
}

const applyPatch = module.exports.applyPatch =
function applyPatch (patch, dep, packageJSON) {
if (!Object.prototype.hasOwnProperty.call(packageJSON.dependencies, dep)) {
throw new Error('Dependency not found in package.json')
}
packageJSON.dependencies[dep] = patch
return packageJSON
}

async function pushPatch (packageJSON, owner, repo, dep) {
const file = JSON.stringify(packageJSON, null, 2) + '\n' // assumes package.json is using two spaces
const encodedFile = Buffer.from(file).toString('base64')
const message = `wiby: update ${dep}`
const branch = `wiby-${dep}`

const [headSha, treeSha] = await github.getShas(owner, repo)
const blobSha = await github.createBlob(owner, repo, encodedFile)
const newTreeSha = await github.createTree(owner, repo, treeSha, blobSha)
const commitSha = await github.createCommit(owner, repo, message, newTreeSha, headSha)
await github.createBranch(owner, repo, commitSha, branch)
console.log(`Changes pushed to https://github.com/${owner}/${repo}/blob/${branch}/package.json`)
}
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@
"url": "https://github.com/pkgjs/wiby/issues"
},
"homepage": "https://github.com/pkgjs/wiby#readme",
"dependencies": {},
"dependencies": {
"@octokit/graphql": "^4.5.0",
"@octokit/rest": "^17.9.2",
"dotenv": "^8.2.0",
"node-fetch": "^2.6.0",
"yargs": "^15.3.1"
},
"devDependencies": {
"standard": "^14.3.4",
"tap": "^14.10.7"
Expand Down
48 changes: 48 additions & 0 deletions test/fixtures/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module.exports.DEP_URL = 'https://github.com/andrewhughes101/do-you-pass'
module.exports.PKGJSON = {
name: 'do-you-pass',
version: '1.0.0',
description: 'Does i-should-pass pass?',
main: 'index.js',
scripts: {
test: 'node test.js'
},
author: 'Andrew Hughes',
license: 'Apache-2.0',
homepage: 'https://github.com/andrewhughes101/do-you-pass',
repository: {
type: 'git',
url: 'https://github.com/andrewhughes101/do-you-pass.git'
},
dependencies: {
'i-should-pass': '^1.0.0'
}
}
module.exports.PATCHED_PKGJSON = {
name: 'do-you-pass',
version: '1.0.0',
description: 'Does i-should-pass pass?',
main: 'index.js',
scripts: {
test: 'node test.js'
},
author: 'Andrew Hughes',
license: 'Apache-2.0',
homepage: 'https://github.com/andrewhughes101/do-you-pass',
repository: {
type: 'git',
url: 'https://github.com/andrewhughes101/do-you-pass.git'
},
dependencies: {
'i-should-pass': 'andrewhughes101/i-should-pass#ec218ed4d7bd085c4aa3d94c2f86a43470754816'
}
}
module.exports.PATCH = 'andrewhughes101/i-should-pass#ec218ed4d7bd085c4aa3d94c2f86a43470754816'
module.exports.PKG_NAME = 'i-should-pass'
module.exports.PKG_REPO = 'i-should-pass'
module.exports.PKG_ORG = 'andrewhughes101'
module.exports.DEP_REPO = 'do-you-pass'
module.exports.DEP_ORG = 'andrewhughes101'
module.exports.PKG_HEAD_SHA = 'ec218ed4d7bd085c4aa3d94c2f86a43470754816'
module.exports.LOCAL = 'i-should-pass'
module.exports.DEP_REPO_PERM = 'ADMIN'
19 changes: 19 additions & 0 deletions test/fixtures/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "do-you-pass",
"version": "1.0.0",
"description": "Does i-should-pass pass?",
"main": "index.js",
"scripts": {
"test": "node test.js"
},
"author": "Andrew Hughes",
"license": "Apache-2.0",
"homepage": "https://github.com/andrewhughes101/do-you-pass",
"repository": {
"type": "git",
"url": "https://github.com/andrewhughes101/do-you-pass.git"
},
"dependencies": {
"i-should-pass": "^1.0.0"
}
}
13 changes: 13 additions & 0 deletions test/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require('dotenv').config()
const tap = require('tap')
const github = require('../lib/github')
const CONFIG = require('./fixtures/config')

tap.test('package.json can be fetched with a valid url', async tap => {
tap.equal(JSON.stringify(await github.getPackageJson(CONFIG.DEP_ORG, CONFIG.DEP_REPO)), JSON.stringify(CONFIG.PKGJSON))
// tap.throws( await pkgTest.getPackageJson('not-an-org', 'not-a-repo'))
})

tap.test('correct permissions returned for GitHub repo', async tap => {
tap.equal((await github.getPermissions(CONFIG.DEP_ORG, CONFIG.DEP_REPO)), CONFIG.DEP_REPO_PERM)
})
Loading

0 comments on commit a80429a

Please sign in to comment.