question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Provide primitives for "if this file exists, then so should this" sort of rules

See original GitHub issue

Basically, provide some kind of way to simplify rules like these

// Check that every file touched has a corresponding test file
const correspondingTestsForModifiedFiles = modifiedFiles.map(f => {
  const newPath = path.dirname(f);
  const name = path.basename(f);
  return `${newPath}/__tests__/${name}`;
});

const testFilesThatDontExist = correspondingTestsForModifiedFiles
  .filter(f => !f.includes('__stories__')) // skip stories
  .filter(f => !fs.existsSync(f));

if (testFilesThatDontExist.length > 0 && !skipTests) {
  const output = `Missing Test Files:
${testFilesThatDontExist.map(f => `- \`${f}\``).join('\n')}
If these files are supposed to not exist, please update your PR body to include "Skip New Tests".`;
  warn(output);
}

// Find changed React components
const changedComponents = modifiedFiles.filter(file => {
  const content = fs.readFileSync(file).toString();
  return content.includes('React');
});

// Check for images in PR description if new components added
if (changedComponents.length > 0 && !skipVisualDiff && !hasScreenShots) {
  const output = `Should there be images to represent these components:
  ${changedComponents.map(f => `- \`${f}\``).join('\n')}
  If these changes are not visual, please update your PR body to include "Skip Visual Diff".`;
  warn(output);
}

// Check that every component touched has a corresponding story
const correspondingStoriesForChangedComponents = uniq(
  changedComponents.map(f => {
    const newPath = path.dirname(f);
    return `${newPath}/__stories__/index.js`;
  })
);

const missingStories = correspondingStoriesForChangedComponents.filter(
  f => !fs.existsSync(f)
);

and

// Custom modifiers for people submitting PRs to be able to say "skip this"
const trivialPR = bodyAndTitle.includes("trivial")
const acceptedNoTests = bodyAndTitle.includes("skip new tests")

const typescriptOnly = (file: string) => includes(file, ".ts")
const filesOnly = (file: string) => fs.existsSync(file) && fs.lstatSync(file).isFile()

// Custom subsets of known files
const modifiedAppFiles = modified.filter(p => includes(p, "lib/")).filter(p => filesOnly(p) && typescriptOnly(p))

// Modified or Created can be treated the same a lot of the time
const touchedFiles = modified.concat(danger.git.created_files).filter(p => filesOnly(p))

const touchedAppOnlyFiles = touchedFiles.filter(
  p => includes(p, "src/lib/") && !includes(p, "__tests__") && typescriptOnly(p)
)

const touchedComponents = touchedFiles.filter(p => includes(p, "src/lib/components") && !includes(p, "__tests__"))

// Rules
// When there are app-changes and it's not a PR marked as trivial, expect
// there to be CHANGELOG changes.
const changelogChanges = includes(modified, "CHANGELOG.md")
if (modifiedAppFiles.length > 0 && !trivialPR && !changelogChanges) {
  fail("No CHANGELOG added.")
}

// Check that every file touched has a corresponding test file
const correspondingTestsForAppFiles = touchedAppOnlyFiles.map(f => {
  const newPath = path.dirname(f)
  const name = path.basename(f).replace(".ts", "-tests.ts")
  return `${newPath}/__tests__/${name}`
})

// New app files should get new test files
// Allow warning instead of failing if you say "Skip New Tests" inside the body, make it explicit.
const testFilesThatDontExist = correspondingTestsForAppFiles
  .filter(f => !f.includes("Index-tests.tsx")) // skip indexes
  .filter(f => !f.includes("types-tests.ts")) // skip type definitions
  .filter(f => !f.includes("__stories__")) // skip stories
  .filter(f => !f.includes("AppRegistry")) // skip registry, kinda untestable
  .filter(f => !f.includes("Routes")) // skip routes, kinda untestable
  .filter(f => !f.includes("NativeModules")) // skip modules that are native, they are untestable
  .filter(f => !f.includes("lib/relay/")) // skip modules that are native, they are untestable
  .filter(f => !f.includes("Storybooks/")) // skip modules that are native, they are untestable
  .filter(f => !fs.existsSync(f))

if (testFilesThatDontExist.length > 0) {
  const callout = acceptedNoTests ? warn : fail
  const output = `Missing Test Files:
${testFilesThatDontExist.map(f => `- \`${f}\``).join("\n")}
If these files are supposed to not exist, please update your PR body to include "Skip New Tests".`
  callout(output)
}

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:1
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
ortacommented, Apr 5, 2019

Micromatch is a good call, because jest uses it - and there’s probably a big overlap in Jest and Danger users.

My preference is always to keep the Danger dep tree matching with Jest when I have any choices to make.

OK, so, let’s vendor in the micromatch index.js into danger somewhere, add it to the git DSL - if you get it working in a PR, I can handle all of the documentation side of it and wrap it up

1reaction
ortacommented, Apr 5, 2019

No I think you’re a bit off base , Danger doesn’t provide rules - Danger provides tools to make rules. This issue is about providing another API function which does a good job of making it easy to do file checking.

An example of resolving this issue is chainsmoker by @paulmelnikow

Perhaps Danger could depend on it, and expose the chainsmoker as default export:

import {danger} from "danger"

// danger.git.match = 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 = danger.git.match(
  '**/*.md',
  'lib/all-badge-examples.js',
  'frontend/components/usage.js'
)
const packageJson = danger.git.match('package.json')
const packageLock = danger.git.match('package-lock.json')
const helpers = danger.git.match('lib/**/*.js', '!**.spec.js')
const helperTests = danger.git.match('lib/**/*.spec.js')

// This is `true` whenever there are matches in the corresponding path array.
if (documentation.createdOrModified) {
  message('We :heart: our [documentarians](http://www.writethedocs.org/)!')
}

if (packageJson.modified && !packageLock.modified) {
  warn('This PR modified package.json, but not package-lock.json')
}

if (helpers.created && !helperTests.created) {
  warn('This PR added helper modules in lib/ but not accompanying tests.')
} else if (helpers.createdOrModified && !helperTests.createdOrModified) {
  warn('This PR modified helper modules in lib/ but not accompanying tests.')
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Manipulating File Names - Lugaru Software Ltd.
First (for either primitive), if the specified file name is an absolute pathname, Epsilon simply checks to see if the file exists, and...
Read more >
How to check if a variable's type is primitive? - Stack Overflow
So by this rule, type and function are not primitive? I'm sure there is a way for OP to rephrase his/her code so...
Read more >
Polar Syntax - Oso Library Documentation
Rules allow you to express conditional statements ("if this then that"). A rule in Polar takes the form HEAD if BODY; where HEAD...
Read more >
Extensibility - Fluent Assertions
It's the returned assertions class that provides the actual assertion methods. ... FailWith("You can't assert a file exist if you don't pass a...
Read more >
Chapter 5. The Rule Language - JBoss.org
In a DRL file you can have multiple rules, queries and functions, as well as some ... 1: rule one 2: when 3:...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found