Skip to content

Commit

Permalink
feat: initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed Sep 5, 2017
1 parent 2d88700 commit 8888a3b
Show file tree
Hide file tree
Showing 14 changed files with 792 additions and 0 deletions.
137 changes: 137 additions & 0 deletions bin/record.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env node

const axios = require('axios')
const chalk = require('chalk')
const {diff, diffString} = require('json-diff')
const glob = require('glob')
const humanize = require('humanize-string')
const nock = require('nock')

const env = require('../lib/env')
const isTravisCronJob = require('../lib/is-travis-cron-job')
const normalize = require('../lib/normalize')
const notifyAboutFixturesChanges = require('../lib/notify-about-fixtures-changes')
const read = require('../lib/read')
const write = require('../lib/write')

const argv = require('minimist')(process.argv.slice(2), {
boolean: 'update'
})
const doUpdate = argv.update
const selectedScenarios = argv._
const hasSelectedScenarios = selectedScenarios.length > 0

nock.recorder.rec({
output_objects: true,
dont_print: true,
enable_reqheaders_recording: true
})

const scenarios = hasSelectedScenarios ? selectedScenarios : glob.sync('scenarios/**/*.js')
const diffs = []

// run scenarios one by one
scenarios.reduce(async (promise, scenarioPath) => {
await promise
const fixtureName = scenarioPath.replace(/(^scenarios\/|\.js$)/g, '')
const [domain, title] = fixtureName.split('/')
console.log('')
console.log(`⏯️ ${chalk.bold(domain)}: ${humanize(title.replace('.js', ''))} ...`)

const scenario = require(`../scenarios/${fixtureName}`)
let baseURL = `https://${domain}`

// workaround for https://github.com/gr2m/octokit-fixtures/issues/3
if (domain === 'api.github.com' && env.FIXTURES_PROXY) {
baseURL = env.FIXTURES_PROXY
}

if (Array.isArray(scenario)) {
// if scenario is an array of request options, send requests sequentially
await scenario.reduce(async (promise, step) => {
try {
await promise
} catch (error) {
// don’t fail on 4xx errors, they are valid fixtures
if (error.response.status >= 500) {
throw error
}
}

return axios.create({baseURL})(step)
}, Promise.resolve())
} else if (typeof scenario === 'object') {
// if scenario is an object with request options, send a request for it
await axios.create({baseURL})(scenario)
} else {
// otherwise we expect scenario to be an asynchronous function
await scenario()
}

const newFixtures = nock.recorder.play().map(normalize)
const oldFixtures = await read(fixtureName)
nock.recorder.clear()

const fixturesDiffs = diff(newFixtures, oldFixtures)
if (fixturesDiffs) {
diffs.push({
name: fixtureName,
changes: fixturesDiffs,
newFixtures,
oldFixtures
})
if (fixturesDiffs[0][0] === '-') {
if (doUpdate) {
console.log(`📼 New fixtures recorded`)
return write(fixtureName, newFixtures)
}
console.log(`❌ This looks like a new fixture`)
} else {
if (doUpdate) {
console.log(`📼 Fixture updates recorded`)
return write(fixtureName, newFixtures)
}
console.log(`❌ Fixtures are not up-to-date`)

if (!isTravisCronJob()) {
console.log(diffString(oldFixtures, newFixtures))
console.log(`💁 Update fixtures with \`${chalk.bold('bin/record.js --update')}\``)
}
}
} else {
console.log(`✅ Fixtures are up-to-date`)
}

return Promise.resolve()
}, Promise.resolve())

.then(() => {
if (diffs.length === 0) {
if (isTravisCronJob()) {
console.log('🤖 No fixture changes detected in cron job.')
}
return
}

if (doUpdate) {
return
}

if (isTravisCronJob()) {
return notifyAboutFixturesChanges(diffs)
}

console.log(`${diffs.length} fixtures are out of date. Exit 1`)
process.exit(1)
})

.catch((error) => {
if (!error.response) {
console.log(error)
process.exit(1)
}

console.log(error.toString())
console.log(JSON.stringify(error.response.data, null, 2))
process.exit(1)
})
38 changes: 38 additions & 0 deletions bin/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env node

const express = require('express')
const glob = require('glob')
const nock = require('nock')
const proxy = require('http-proxy-middleware')

const fixturePaths = glob.sync('fixtures/api.github.com/*.json')
fixturePaths.map(nock.load).forEach((fixtureMocks) => {
// by default, nock only allows each mocked route to be called once, afterwards
// it returns a "No match for request" error. mock.persist() works around that
fixtureMocks.forEach(mock => mock.persist())
})

const app = express()
app.use('/', proxy({
target: 'https://api.github.com',
changeOrigin: true,
loglevel: 'debug',
onError (error, request, response) {
response.writeHead(500, {
'Content-Type': 'application/json; charset=utf-8'
})

if (error.message.indexOf('Nock: No match for request') !== 0) {
return response.end(error.message)
}

const errorRequestJson = JSON.parse(error.message.substr('Nock: No match for request '.length))

response.end(JSON.stringify({
error: 'Nock: No match for request',
request: errorRequestJson
}, null, 2) + '\n')
}
}))
app.listen(3000)
console.log('🌐 http://localhost:3000')
130 changes: 130 additions & 0 deletions fixtures/api.github.com/get-repository.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
[
{
"scope": "https://api.github.com:443",
"method": "get",
"path": "/repos/octocat/hello-world",
"body": "",
"status": 200,
"response": {
"id": 1296269,
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"owner": {
"login": "octocat",
"id": 583231,
"avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"private": false,
"html_url": "https://github.com/octocat/Hello-World",
"description": "My first repository on GitHub!",
"fork": false,
"url": "https://api.github.com/repos/octocat/Hello-World",
"forks_url": "https://api.github.com/repos/octocat/Hello-World/forks",
"keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/octocat/Hello-World/teams",
"hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks",
"issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}",
"events_url": "https://api.github.com/repos/octocat/Hello-World/events",
"assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}",
"branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}",
"tags_url": "https://api.github.com/repos/octocat/Hello-World/tags",
"blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}",
"languages_url": "https://api.github.com/repos/octocat/Hello-World/languages",
"stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers",
"contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors",
"subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers",
"subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription",
"commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}",
"compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/octocat/Hello-World/merges",
"archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads",
"issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}",
"pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}",
"milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}",
"notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}",
"releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}",
"deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments",
"created_at": "2017-10-10T16:00:00Z",
"updated_at": "2017-10-10T16:00:00Z",
"pushed_at": "2017-10-10T16:00:00Z",
"git_url": "git://github.com/octocat/Hello-World.git",
"ssh_url": "[email protected]:octocat/Hello-World.git",
"clone_url": "https://github.com/octocat/Hello-World.git",
"svn_url": "https://github.com/octocat/Hello-World",
"homepage": "",
"size": 578,
"stargazers_count": 42,
"watchers_count": 42,
"language": null,
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 42,
"mirror_url": null,
"open_issues_count": 42,
"forks": 42,
"open_issues": 42,
"watchers": 42,
"default_branch": "master",
"network_count": 42,
"subscribers_count": 42
},
"reqheaders": {
"accept": "application/vnd.github.v3+json",
"host": "api.github.com"
},
"headers": {
"access-control-allow-origin": "*",
"access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval",
"cache-control": "public, max-age=60, s-maxage=60",
"connection": "close",
"content-length": "4721",
"content-security-policy": "default-src 'none'",
"content-type": "application/json; charset=utf-8",
"date": "Tue, 10 Oct 2017 16:00:00 GMT",
"etag": "\"00000000000000000000000000000000\"",
"last-modified": "Tue, 10 Oct 2017 16:00:00 GMT",
"status": "200 OK",
"strict-transport-security": "max-age=31536000; includeSubdomains; preload",
"x-content-type-options": "nosniff",
"x-frame-options": "deny",
"x-github-media-type": "github.v3; format=json",
"x-github-request-id": "0000:00000:0000000:0000000:00000000",
"x-ratelimit-limit": "60",
"x-ratelimit-remaining": "59",
"x-ratelimit-reset": "1507651200000",
"x-runtime-rack": "0.000000",
"x-xss-protection": "1; mode=block"
},
"badheaders": [
"authorization"
]
}
]
Loading

0 comments on commit 8888a3b

Please sign in to comment.