The CSS in the project is relatively difficult to change. While it is very DRY, it relies heavily on inheritance. It's difficult to make changes in the markup modal without it also affecting styles elsewhere. [styled-components](https://www.styled-components.com/) is one of the leading CSS-in-JS libraries. By reducing dependency on global state and CSS inheritance, styles become explicit and are easier to inspect and change. It's also convenient that styles can be embedded with the components they modify. At runtime, the library creates CSS classes, so it's pretty efficient. We were using a little bit of [styled-jsx](https://github.com/zeit/styled-jsx) before, which ships with Next.js, though styled-components is more widely used and I've had good experiences with it all around. In a few cases I've duplicated styles where it feels more natural to do that: for example, `text-align: center` is duplicated in `Main` and `MarkupModal`. Much of this is a refactor, though there are a few visual changes, particularly in the markup modal and the style examples.
170 lines
4.7 KiB
JavaScript
170 lines
4.7 KiB
JavaScript
'use strict'
|
|
|
|
// Have you identified a contributing guideline that should be included here?
|
|
// Please open a pull request!
|
|
//
|
|
// To test changes to this file, pick a PR to test against, then run
|
|
// `./node_modules/.bin/danger pr pr-url`
|
|
// Note that the line numbers in the runtime errors are incorrect.
|
|
|
|
const { danger, fail, message, warn } = require('danger')
|
|
const chainsmoker = require('chainsmoker')
|
|
const { default: noTestShortcuts } = require('danger-plugin-no-test-shortcuts')
|
|
|
|
const fileMatch = chainsmoker({
|
|
created: danger.git.created_files,
|
|
modified: danger.git.modified_files,
|
|
createdOrModified: danger.git.modified_files.concat(danger.git.created_files),
|
|
deleted: danger.git.deleted_files,
|
|
})
|
|
|
|
const documentation = fileMatch(
|
|
'**/*.md',
|
|
'lib/all-badge-examples.js',
|
|
'frontend/components/usage.js'
|
|
)
|
|
const server = fileMatch('server.js')
|
|
const serverTests = fileMatch('server.spec.js')
|
|
const helpers = fileMatch(
|
|
'lib/**/*.js',
|
|
'!**/*.spec.js',
|
|
'!lib/all-badge-examples.js'
|
|
)
|
|
const logos = fileMatch('logo/*.svg')
|
|
const helperTests = fileMatch('lib/**/*.spec.js')
|
|
const packageJson = fileMatch('package.json')
|
|
const packageLock = fileMatch('package-lock.json')
|
|
const capitals = fileMatch('**/*[A-Z]*.js')
|
|
// _document.js is used by convention by Next.
|
|
const underscores = fileMatch('**/*_*.js', '!pages/_document.js')
|
|
const targetBranch = danger.github.pr.base.ref
|
|
|
|
message(
|
|
[
|
|
':sparkles: Thanks for your contribution to Shields, ',
|
|
`@${danger.github.pr.user.login}!`,
|
|
].join('')
|
|
)
|
|
|
|
if (targetBranch !== 'master') {
|
|
const message = `This PR targets \`${targetBranch}\``
|
|
const idea = 'It is likely that the target branch should be `master`'
|
|
warn(`${message} - <i>${idea}</i>`)
|
|
}
|
|
|
|
if (documentation.createdOrModified) {
|
|
message(
|
|
[
|
|
'Thanks for contributing to our documentation. ',
|
|
'We :heart: our [documentarians](http://www.writethedocs.org/)!',
|
|
].join('')
|
|
)
|
|
}
|
|
|
|
if (packageJson.modified && !packageLock.modified) {
|
|
const message = 'This PR modified `package.json`, but not `package-lock.json`'
|
|
const idea = 'Perhaps you need to run `npm install`?'
|
|
warn(`${message} - <i>${idea}</i>`)
|
|
}
|
|
|
|
if (server.modified && !serverTests.modified) {
|
|
warn(
|
|
[
|
|
'This PR modified the server but none of its tests. <br>',
|
|
"That's okay so long as it's refactoring existing code.",
|
|
].join('')
|
|
)
|
|
}
|
|
|
|
if (helpers.created && !helperTests.created) {
|
|
warn(
|
|
[
|
|
'This PR added helper modules in `lib/` but not accompanying tests. <br>',
|
|
'Generally helper modules should have their own tests.',
|
|
].join('')
|
|
)
|
|
} else if (helpers.createdOrModified && !helperTests.createdOrModified) {
|
|
warn(
|
|
[
|
|
'This PR modified helper functions in `lib/` but not accompanying tests. <br>',
|
|
"That's okay so long as it's refactoring existing code.",
|
|
].join('')
|
|
)
|
|
}
|
|
|
|
if (logos.created) {
|
|
message(
|
|
[
|
|
':art: Thanks for submitting a logo. <br>',
|
|
'Please ensure your contribution follows our ',
|
|
'[guidance](https://github.com/badges/shields/blob/master/CONTRIBUTING.md#logos) ',
|
|
'for logo submissions.',
|
|
].join('')
|
|
)
|
|
}
|
|
|
|
if (capitals.created || underscores.created) {
|
|
fail(
|
|
[
|
|
'JavaScript source files should be named with `kebab-case` ',
|
|
'(dash-separated lowercase).',
|
|
].join('')
|
|
)
|
|
}
|
|
|
|
const allFiles = danger.git.created_files.concat(danger.git.modified_files)
|
|
|
|
allFiles.forEach(file => {
|
|
// eslint-disable-next-line promise/prefer-await-to-then
|
|
danger.git.diffForFile(file).then(diff => {
|
|
if (/\+.*assert[(.]/.test(diff.diff)) {
|
|
warn(
|
|
[
|
|
`Found 'assert' statement added in \`${file}\`. <br>`,
|
|
'Please ensure tests are written using Chai ',
|
|
'[expect syntax](http://chaijs.com/guide/styles/#expect)',
|
|
].join('')
|
|
)
|
|
}
|
|
})
|
|
})
|
|
|
|
function onlyUnique(value, index, self) {
|
|
return self.indexOf(value) === index
|
|
}
|
|
|
|
const affectedServices = allFiles
|
|
.map(file => {
|
|
const match = file.match(/^services\/(.+)\/.+\.service.js$/)
|
|
return match ? match[1] : undefined
|
|
})
|
|
.filter(Boolean)
|
|
.filter(onlyUnique)
|
|
|
|
const testedServices = allFiles
|
|
.map(file => {
|
|
const match = file.match(/^services\/(.+)\/.+\.tester.js$/)
|
|
return match ? match[1] : undefined
|
|
})
|
|
.filter(Boolean)
|
|
.filter(onlyUnique)
|
|
|
|
affectedServices.forEach(service => {
|
|
if (testedServices.indexOf(service) === -1) {
|
|
warn(
|
|
[
|
|
`This PR modified service code for <kbd>${service}</kbd> but not its test code. <br>`,
|
|
"That's okay so long as it's refactoring existing code.",
|
|
].join('')
|
|
)
|
|
}
|
|
})
|
|
|
|
// Prevent merging exclusive services tests.
|
|
noTestShortcuts({
|
|
testFilePredicate: filePath => filePath.endsWith('.tester.js'),
|
|
patterns: {
|
|
only: ['only()'],
|
|
},
|
|
})
|