How Artsy Automates Team Culture

How Artsy Automates Team Culture

0ebf471a3ae8df42a84f93a7efbbdbd0?s=128

Ash Furrow

May 31, 2019
Tweet

Transcript

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9.
  10. 10.
  11. 11.
  12. 12.
  13. 13.
  14. 14.
  15. 16.
  16. 17.

    build_file = File.join(ENV["CIRCLE_ARTIFACTS"], "xcode_build_raw.log") # Sort the symbols, then grab

    the top 1000 most_expensive_swift_table = `…` # Some command-line stuff # Look for statistical outliers in compile times outliers = most_expensive_swift_table .lines.map { |line| line.split.first.to_i } .reject { |value| value "# 0 } .outliers(3) if outliers.any? warn("Detected some Swift building time outliers") headings = "Time | Class | Function |\n| ""$ | ----- | ----- |" warnings = ""% # Construct a Markdown table markdown(([headings] + warnings).join) end
  17. 18.
  18. 19.
  19. 20.
  20. 21.

    # Ask to update Chinese docs if only English docs

    are updated and vice-versa. en_docs_modified = git.modified_files.grep(%r{docs/}).empty? cn_docs_modified = git.modified_files.grep(%r{docs_CN}).empty? # xor operator ftw if en_docs_modified ^ cn_docs_modified warn("Consider "&also"& updating the "' en_docs_modified ? "English" : "Chinese" } docs.") end
  21. 22.
  22. 23.
  23. 25.

    { "settings": { "ignored_repos": ["artsy/design", "artsy/hokusai"] }, "rules": { "(

    Jira integration "pull_request": "org/allPRs.ts", "pull_request.closed": ["org/closedPRs.ts", "org/jira/pr.ts"], "pull_request.opened": "org/addPatchLabel.ts", "( The RFC process "issues": "org/rfc/addRFCToNewIssues.ts", "issues.labeled": "org/rfc/scheduleRFCsForLabels.ts", "( Merge on Green "issue_comment": "org/markAsMergeOnGreen.ts", "pull_request_review": "org/markAsMergeOnGreen.ts", "status.success": "org/mergeOnGreen.ts" }, "repos": { "artsy/peril-settings": { "pull_request.review_requested": "org/addReviewer.ts" },
  24. 26.

    { "settings": { "ignored_repos": ["artsy/design", "artsy/hokusai"] }, "rules": { "(

    Jira integration "pull_request": "org/allPRs.ts", "pull_request.closed": ["org/closedPRs.ts", "org/jira/pr.ts"], "pull_request.opened": "org/addPatchLabel.ts", "( The RFC process "issues": "org/rfc/addRFCToNewIssues.ts", "issues.labeled": "org/rfc/scheduleRFCsForLabels.ts", "( Merge on Green "issue_comment": "org/markAsMergeOnGreen.ts", "pull_request_review": "org/markAsMergeOnGreen.ts", "status.success": "org/mergeOnGreen.ts" }, "repos": { "artsy/peril-settings": { "pull_request.review_requested": "org/addReviewer.ts" },
  25. 27.

    { "settings": { "ignored_repos": ["artsy/design", "artsy/hokusai"] }, "rules": { "(

    Jira integration "pull_request": "org/allPRs.ts", "pull_request.closed": ["org/closedPRs.ts", "org/jira/pr.ts"], "pull_request.opened": "org/addPatchLabel.ts", "( The RFC process "issues": "org/rfc/addRFCToNewIssues.ts", "issues.labeled": "org/rfc/scheduleRFCsForLabels.ts", "( Merge on Green "issue_comment": "org/markAsMergeOnGreen.ts", "pull_request_review": "org/markAsMergeOnGreen.ts", "status.success": "org/mergeOnGreen.ts" }, "repos": { "artsy/peril-settings": { "pull_request.review_requested": "org/addReviewer.ts" },
  26. 28.

    • Requires Per-repo setup • Simpler to get started •

    Ruby, JS, Swift, more… • Setup once per GitHub Org • Requires hosting • Far more powerful • TypeScript/JS
  27. 29.
  28. 30.

    export default async () ") { const pr = danger.github.pr

    if (pr.body.includes("#trivial")) { return } const changelogs = ["CHANGELOG.md", "changelog.md", "CHANGELOG.yml"] "( Some code to check if the repo has one of these files in it. if (isPROpen "* repoHasChangelog) { const files = [""%danger.git.modified_files, ""%danger.git.created_files] const hasCodeChanges = files.find(file ") !file.match(/(test|spec)/i)) const hasChangelogChanges = files.find(file ") changelogs.includes(file)) if (hasCodeChanges "* !hasChangelogChanges) { warn("…") } } }
  29. 31.
  30. 32.

    import { danger, warn, fail } from "danger" const mobileRepos

    = ["eigen", "emission", "eidolon", "energy", "emergence"] export default async () ") { const pr = danger.github.pr const isMobileRepo = mobileRepos.filter(name ") pr.base.repo.name.endsWith(name) ).length > 0 if (isMobileRepo "* pr.head.repo.fork) { try { "( Are they a member of the Artsy GitHub org? This will throw if not. await danger.github.api.orgs.checkMembership( { org: "artsy", username: pr.user.login } ) fail("…") } catch (error) { "( They are not. } } }
  31. 33.
  32. 34.
  33. 35.
  34. 37.
  35. 38.
  36. 39.
  37. 41.
  38. 42.
  39. 43.
  40. 44.
  41. 45.
  42. 46.
  43. 47.
  44. 48.
  45. 49.
  46. 50.
  47. 51.
  48. 52.
  49. 53.
  50. 54.
  51. 55.
  52. 56.
  53. 57.
  54. 58.
  55. 59.
  56. 60.