{"id":13462285,"url":"https://github.com/SquareSquash/web","last_synced_at":"2025-03-25T01:31:59.853Z","repository":{"id":5834126,"uuid":"7049909","full_name":"SquareSquash/web","owner":"SquareSquash","description":"Squash’s front-end and API host.","archived":false,"fork":false,"pushed_at":"2020-10-04T06:15:07.000Z","size":3634,"stargazers_count":962,"open_issues_count":44,"forks_count":134,"subscribers_count":46,"default_branch":"master","last_synced_at":"2024-10-29T11:11:03.005Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://www.squash.io","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SquareSquash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-07T08:18:02.000Z","updated_at":"2024-10-16T04:42:59.000Z","dependencies_parsed_at":"2022-08-31T21:24:22.205Z","dependency_job_id":null,"html_url":"https://github.com/SquareSquash/web","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SquareSquash%2Fweb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SquareSquash%2Fweb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SquareSquash%2Fweb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SquareSquash%2Fweb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SquareSquash","download_url":"https://codeload.github.com/SquareSquash/web/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245382125,"owners_count":20606157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T12:00:43.743Z","updated_at":"2025-03-25T01:31:58.774Z","avatar_url":"https://github.com/SquareSquash.png","language":"Ruby","readme":"Squash: A squarish bug spray\n============================\n\n**An open-source project from [Square](http://github.com/square)**\n\nSquash is a collection of tools that help engineers find and kill bugs in their\ncode by automatically collecting, collating and analyzing run time exceptions.\nSquash consists of the following components:\n\n* **Client libraries:** Client libraries for different systems (Ruby, Ruby on\n  Rails, Cocoa with Objective-C, etc.) catch and record errors when they occur,\n  then send them to the API endpoint. Client libraries can be found under the\n  [SquareSquash organization](https://github.com/SquareSquash).\n* **Front-end:** This website displays Bug information and helps the engineer\n  find the root cause for a Bug, and fix it. It also lets engineers manage,\n  assign, and comment on Bugs, as well as view statistics about the Bug.\n* **API endpoints:** These routes (part of the front-end app) receive exception\n  notifications from the client libraries and process them.\n\nThis project is the front-end and the API.\n\nPull requests are more than welcome; please check out\n[CONTRIBUTING.md](file.CONTRIBUTING.html) for details.\n\nHow to Install\n--------------\n\nTo get started, run the `bin/setup` file. This script will ask you a series of \nquestions and generate a preliminary configuration for your site install. When \nthe script is completed, you can run `git status` to see what files it changed, \nand refine your configuration from there.\n\nOnce the script is complete, Squash should run for most typical development\nenvironments. Simply run `rails s` and visit the site in your Web browser. You\nshould be able to start using it immediately. You can also verify correctness by\nrunning `rspec spec`.\n\nConfiguring and deploying the production instance is entirely up to you and your\nparticular production environment.\n\nAdditional configuration options can be found in the following locations:\n\n* `config/application.rb`\n* `config/environments/*.rb`\n* `config/environments/*/*.yml`\n\nIf you don't see what you're looking for in any of those files, you'll probably\nhave to change the code to make it work. Don't be afraid -- the code is\nthoroughly documented and should (hopefully) be very accessible.\n\n### Requirements\n\nSquash requires the following:\n\n* Ruby 1.9.2 or newer (JRuby with `--1.9` is supported)\n* Multithreading support (see the next section)\n* PostgreSQL 9.1 or newer\n* The Bundler gem\n* Git 1.7 or newer\n\n### Notes on some of the gem and library choices\n\n**Why do you specifically require PostgreSQL?** Squash uses a lot of\nPostgreSQL-specific features to make efficient use of the database and maintain\nreferential integrity, such as:\n\n* foreign key constraints,\n* triggered cached counters,\n* check constraints, and\n* semantic indexes for text-based search.\n\nIf PostgreSQL is out of the question, some of these features can be ported to\nother RDBMSes; simply edit the `InitialSchema` migration and update the SQL as\nnecessary. If portability is required, a lot of these features can be\nreimplemented in the Rails layer (e.g., cached counters), at the risk of\ndegraded referential integrity. (If you are reimplementing the cached counters\nin Ruby, be sure to modify the `config/initializers/active_record.rb` file as\nappropriate.)\n\nIf you do successfully port Squash to another RDBMS, let me know. I'd be happy\nto take your changes.\n\n**Why do you bundle an edge version of Rails?** The `3-2-stable` branch of Ruby\non Rails includes some changes to Active Record that are required by Squash's\nmultithreaded concurrency model (see next question). In particular, that version\nof Active Record includes crucial changes to the connection pool and connection\nreopening logic. If you set the `background_runner` option in the\n`concurrency.yml` file to something other than `Multithread`, the Gemfile will\nautomatically drop Rails back down to the latest release version.\n\n**Why don't you use my favorite backgrounding library?** Squash was originally\nbuilt for Square, which runs all its services on JRuby. Using threads is very\nefficient in JRuby, and avoids the overhead of having to deploy both a website\nand workers.\n\nIf you are running Squash in a non-thread-safe (or multithreading-unfriendly)\nenvironment, you can use Sidekiq or Resque instead. If you want to use some\nother backgrounding library, you can easily write your own adapter. All threaded\ncode is invoked using {BackgroundRunner.run}, which then uses the settings in\nthe `concurrency.yml` Configoro file to invoke the correct module under\n`lib/background_runner`. The default is to use {BackgroundRunner::Multithread},\nwhich uses the {Multithread} module to execute the task in its own thread. You\ncan edit the YAML file and switch the background runner to Resque, or implement\nyour own `BackgroundRunner` module. See the {BackgroundRunner} documentation for\nmore details.\n\nIf you do this successfully and wish to save future Squash users the effort,\nfeel free to turn your changes into a pull request.\n\n**Why aren't you using RedCarpet?** As mentioned above, Squash was originally\nbuilt to run under JRuby. RedCarpet has compiled C extensions; Kramdown is pure\nRuby.\n\n**Why do you require a recent version of Git?** Squash uses the\n`git clone --mirror` command to create local mirrors of client projects' Git\nrepositories.\n\n**Why don't you have integration tests or acceptance tests?** To be 100% honest,\nlack of familiarity on these things in Ruby/Rails. Happy for any help people\nwant to extend towards this goal.\n\n**Why are you using Erector?** I like Erector.\n\nDocumentation\n-------------\n\nComprehensive documentation is written in YARD- and Markdown-formatted comments\nthroughout the source. To view this documentation as an HTML site, run\n`rake yard`.\n\nCoffeeScript libraries are documented using the YARD format as well, but YARD\ndoes not as yet recognize them as documentable files. A `.codoopts` file is\nincluded in case you wish to use [Codo](https://github.com/netzpirat/codo) to\ngenerate the CoffeeScript docs, but as of now Codo does not recognize the ERb\nfiles, and does not use the full set of Markdown syntax features used in the\ndocumentation.\n\nProject Overview\n----------------\n\n### Views\n\nThis is a pretty typical Rails website, save for the views, which are written\nusing Erector. The views forgo the traditional Rails concepts of partials and\ntemplates in favor of analogous OOP concepts more familiar to software\ndevelopers: methods and inheritance. All views inherit from an abstract Erector\nwidget which provides layout; and all views have their content split into\nmultiple private methods.\n\nIn addition to the usual helpers (in `app/helpers`), there are view mixins under\n`app/views/additions` that simplify view coding.\n\nEmbedded code snippets are all rendered using the {CommitsController#context}\naction. This action loads the appropriate file and revision from the Git\nrepository and returns a snippet plus the name of the SyntaxHighlighter brush to\nuse. The brush is determined from the file name/extension; the mapping can be\nfound in `data/brushes.yml`.\n\nThis view behavior is provided from a JavaScript library file in\n`lib/assets/javascripts`. There are many similar helper classes in there; they\nare documented but the documentation is not recognized by YARD and so is not\nincluded in this documentation set.\n\nJavaScript files are organized into four possible locations:\n\n* Third-party JavaScript libraries are in `vendor/assets/javascripts` and\n  loaded in the `application.js` manifest.\n* JavaScript modules or helpers that are not specific to a particular page or\n  site area are in `lib/assets/javascripts` and also loaded in `application.js`.\n* JavaScript modules or helpers specific to a particular area of the site are in\n  `app/assets/javascripts` and also loaded in `application.js`.\n* Small JavaScript snippets, glue code, or other code intended to add dynamic\n  behavior to a specific page is in a `.js` file named the same as, and placed\n  alongside, the `.html.rb` view file. For example, if\n  `app/views/projects/new.html.rb` needed a bit of JS glue code, it would be\n  placed in `app/views/projects/new.js`. This code is placed in a `\u003cSCRIPT\u003e` tag\n  at the end of the view by the {Views::Layouts::Application#inline_javascript}\n  method.\n\nCSS files are similarly organized:\n\n* Third-party CSS files are in `vendor/assets/stylesheets` and loaded in the\n   `application.css` manifest.\n* CSS styles or helpers global to the entire website are in\n  `lib/assets/stylesheets` and also loaded in `application.css`.\n* CSS styles specific to a single page or a related group of pages are placed in\n  `app/assets/stylesheets` and also loaded in `application.css`. Each `\u003cBODY\u003e`\n  tag is given a class name equal to the controller name, and an ID equal to\n  the controller and action name separated with a dash. For instance, the\n  `projects/new` action's body would be `\u003cbody class=projects id=projects-new\u003e`.\n\n### Controllers\n\nFor information about requests and responses, see {ApplicationController}.\n\n### Models\n\nModels make extensive use of advanced PostgreSQL features for efficiency and\nconvenience. Cached counters are updated using triggers and rules, foreign key\nconstraints and hooks are enforced at the database level, and validations are\nbacked up by corresponding `CHECK` triggers. This helps ensure referential and\ndata integrity even in situations where Rails fails, or outside of the Rails\nstack. See the various migrations to learn more about the triggers, rules, and\nconstraints being used.\n\nObservers are used for more high-level triggers, such as creating {Event Events}\nat the appropriate times, or sending emails. See the classes in\n`app/models/observers` for more.\n\nModels also use the HasMetadataColumn gem to reduce their width and incorporate\nschemaless data. Most models have a JSON-formatted `metadata` column to which\nnew information can be added or removed without having to create new migrations.\n\n### Tasks\n\nVarious Rake tasks are available under `lib/tasks`. These include tasks for\npruning and maintaining the database, development tasks, and configuring the\nworkers.\n\n### Workers\n\nWorkers are found in the `lib/workers` directory. Along with OccurrencesWorker,\nwhich stores and categorizes Occurrences, there are other workers for managing\nDeploys and other minor tasks. These workers are run asynchronously using\n{Multithread}.\n\n### Mailers\n\nNotification mails are sent by the {NotificationMailer}. It and any other\nmailers live in `app/mailers`.\n\n`NotificationMailer` conditionally delivers emails. An email will only be\ndelivered if all of the following conditions are met:\n\n* The Project has a mailing list email configured (for the critical-bugs and\n  all-bugs mailing lists),\n* the Environment's `sends_emails` attribute is `true`, and\n* the User has enabled receipt of that category of emails (typically specified\n  in the Membership).\n\n### Authentication and Authorization\n\nAuthentication is done using either password verification or LDAP; see\n{AuthenticationHelpers} and related controller mixins, as well as the\nmodel mixins under `app/models/additions` for more information.\n\nThere are four permissions levels that a User can have, specific to an\nindividual Project:\n\n**Non-members** do not have a {Membership} record with a Project. They can view\nBugs and Occurrences, view the Project's API key, view the list of other\nProject members, watch Bugs, and comment on Bugs.\n\n**Members** can do everything non-members can do, and can also assign Bugs, be\nassigned Bugs, and modify/delete Bugs.\n\n**Administrators** can do everything members can do, and can also modify\nProject and Environment settings, regenerate the API key, promote and demote\nmembers to administrator status, and modify/delete others' Comments.\n\n**Owners** (each Project has only one) can do everything administrators can do,\nand can also delete the Project and reassign ownership.\n\nRecording and Categorizing Occurrences\n--------------------------------------\n\n### Client-Specific Information\n\nThe client library identifiers used throughout the website determine how a Bug\nreported from that library is presented in the view. The\n{OccurrencesController::INDEX_FIELDS} constant maps a client library identifier\nto the relevant summary fields to display in the list view.\n\nEach occurrence is transmitted with the name of the client library; the\n{Occurrence} records this to the `client` field. The {Bug}'s `client` field is\nset from the first Occurrence's; in general, one should expect that all\nOccurrences of a Bug share the same client value.\n\nRegardless of the Occurrence's client value, all fields for which there is data\nare displayed in the Occurrence view.\n\nIf a client library is updated to add new information fields, all that is needed\nis to update the `has_metadata` hash in Occurrence with the new fields, and to\nupdate the `occurrences#show` view as necessary. (The `INDEX_FIELDS` hash can\nalso be updated as appropriate.)\n\nIf a new client library is added, in addition to doing the above for any new\nfields unique to the new client, the `INDEX_FIELDS` hash will need to be\nexpanded to include the new client.\n\n### Queue Consumer\n\nFor information about the background worker that converts incoming exception\ninformation into Occurrence and Bug records (including doing \"best guess\" commit\nblaming, determining which Occurrences share the same root Bug, etc.), see the\ndocumentation for the {OccurrencesWorker} module. See also **Static Analysis**\nbelow.\n\n### Deploys and Releases\n\nSquash can handle both _deployed_ projects (hosted projects for which typically\nonly one version is live at a time) and _released_ projects (distributed apps\nfor which many versions may exist \"in the wild\").\n\nIf you are developing a released project, you must associate your {Deploy}\nobjects with a unique version identifier (such as a build number). You must also\nsend the correct build identifier with every occurrence report. See the client\nlibrary and API controller documentation for more information.\n\nOnce this is done, Squash's behavior is changed slightly: Bugs that are fixed\nin an older release, but recur, are not reopened. Bugs that are fixed in an\nolder release but then recur in newer releases are treated as completely\nseparate Bugs.\n\nThis app exposes an API endpoint for notifying Squash of new releases/deploys of\nyour Project. You should notify Squash whenever you deploy your Project (or\nrelease a new version) so that it can properly manage Bugs (automatically mark\nfixed Bugs as deployed, associate new Bugs with the new Deploy, etc.).\n\nMost client libraries include an easy means to add this feature to your deploy\nor release process.\n\nStatic Analysis\n---------------\n\n### Message Normalization\n\nWhen an Occurrence is grouped into a Bug, its message is stripped of any\nnon-relevant or situational information. (Note that since the message is not\nused as a dimension in grouping Occurrences, two Occurrences of the same Bug\ncould have completely different messages. A Bug gets its message from its first\nOccurrence.) This is done by subclasses of {Blamer::Base}.\n\nFor most messages, this is done using simple regex subsitution. Squash can also\nnormalize an exception's message using a list of known message templates. Such\ntemplates are stored in the `data/message_templates.yml` file. The file contains\na hash mapping exception class names to an array of arrays. Each inner array\ncontains two elements: the regexp to match the exception message on, and the\nreplacement message should it match.\n\nThese templates are evaluated in the order they appear in the array. Scripts\nthat regenerate the templates for MySQL and PostgreSQL error strings can be\nfound under the `script` directory.\n\n### Version Control Systems\n\nAs of now, Squash is only compatible with projects that are version-controlled\nusing Git. However, in the interest of remaining as VCS-agnostic as possible,\ncommit identifiers are never called \"SHA1s,\" but instead \"IDs.\"\n\n### Unsymbolicated, Obfuscated, or Minified Stack Traces\n\nClient libraries of compiled, obfuscated, or minified applications will need to\nconvert their stack traces in order for them to be of use for static analysis.\nBecause release builds are typically not distributed with embedded decompilation\ninformation, a mapping or table must be given to Squash, so that when Squash\nreceives an unconverted stack trace, it can perform lookups and convert it to a\nmore usable format.\n\nCurrently, the supported conversions are:\n\n* symbolication of iOS exceptions (see {Symbolication}),\n* deobfuscation of Java exceptions (see {ObfuscationMap}),\n* and source-mapping of JavaScript exceptions (see {SourceMap}).\n\nClient libraries are responsible for delivering the raw stack trace data to\nSquash when an exception occurs, and for delivering lookup tables to Squash upon\neach new release. {Api::V1Controller} has endpoints for these purposes in\nvarious languages.\n\nUnconverted stack traces are stored in a particular format; see {Occurrence} for\nmore information. When a new exception with a stack trace in this format is\nreceived, Squash immediately attempts to convert it using an existing matching\nlookup table. If no such table is found, the stack trace is left unconverted. It\ncan still be viewed on the front end. When, later, a new lookup table is added,\nSquash automatically finds and converts any matching stack traces.\n\nBecause every new Occurrence must be assigned a Bug (including unconverted\nOccurrences), it is possible that the \"blamed\" `file` and `line` fields of the\nBug could themselves be unconverted. The {Bug} class has provisions to support\nthis; see in particular `bugs.special_file`.\n\nSpecs\n-----\n\nAll models, controllers, and library files are unit-tested with RSpec specs\nunder the `spec` directory. Run unit tests with the `rspec spec` command. Views\nand JavaScript files are not specced. No integration or acceptance tests are\nwritten. Almost all unit tests use factories rather than mocks, putting them\nsomewhat closer to integration tests.\n\nIn general, the test environment is identical to the development/production\nenvironment, save for the usual Rails allowances, and the\n`config/initializers/active_record_observer_hooks.rb` file. This file adds\nafter-commit hooks to observers (identical to those available to models).\nHowever, specs are transactionalized, meaning that these hooks wouldn't run\nuntil after the spec is completed, resulting in multiple spec failures.\n\nTo remedy this, the file introspects on the environment, and instead links the\nobserver hooks to the `after_save` model hooks in the test environment. This\ndifferentiates the test and live environments, but allows specs to pass.\n\nIf you wish to bring your test environment closer to production, you can set\nthe `use_transactional_fixtures` RSpec setting to false. The hooks file will\nautomatically detect the change and use the correct `after_commit` hooks.\nCurrently, all specs pass with and without transactionalized fixtures.\n\nThird-Party Integrations\n------------------------\n\nSquash supports integration with a handful of popular other developer tools.\n\n### PagerDuty\n\nWhen Squash is integrated with PagerDuty, it will begin sending exceptions to\nPagerDuty once the Occurrence count for a given Bug exceeds the Project's\ncritical threshold. Thereafter, every Occurrence is sent to PagerDuty as a\ntrigger. The triggers are grouped into alerts by Bug, so users will only be\npaged once per new error.\n\nIn addition, marking a Bug fixed will also automatically resolve its associated\nPagerDuty alert (if any), and assigning a Bug or marking it irrelevant\nautomatically acknowledges any associated PagerDuty alert.\n\nIn order to integrate Squash with PagerDuty, you must\n\n1. generate an API key that Squash can use for PagerDuty access (you must be a\n   PagerDuty admin to do this),\n2. update the `config/environments/common/pagerduty.yml` file to enable\n   PagerDuty integration and provide the API key,\n3. configure Generic API services for each escalation policy you wish to use,\n   and\n4. set the PagerDuty-related options in your Project's configuration page.\n\n### JIRA\n\nWhen Squash is integrated with JIRA, users have the option of associating a JIRA\nissue with any Bug. The Management tab will then display a link allowing the\nuser to quickly view the associated issue.\n\nIn addition, the user can have Squash watch the JIRA issue for status updates.\nOnce the JIRA issue is resolved (or is changed to someother specified status),\nthe Bug can be automatically marked as fixed. By associating multiple Bugs with\none JIRA issue in such a manner, a user can quickly fix a large number of Bugs\nby closing just one JIRA issue.\n\nFinally, a \"Create JIRA Issue\" button is provided on the Management tab allowing\nusers to easily create new JIRA issues for any Bug.\n\nIn order to integrate Squash with JIRA, you must\n\n1. configure the `config/environments/common/jira.yml` file with your\n   JIRA authentication credentials and installation location, and\n2. add a cron job or other periodic task that runs `rake jira:update`.\n\nJIRA integration works out-of-the-box if you use username/password\nauthentication. OAuth authentication requires a few more steps. Because OAuth\nauthentication requires user actions, you will need to obtain an access token\nand secret which the JIRA client can use without needing to prompt the user. You\ncan do this by running the `jira_oauth.rb` script:\n\n```` ruby\nrails runner script/jira_oauth.rb\n````\n\nFollow the instructions to set up your JIRA integration.\n","funding_links":[],"categories":["Rails","Ruby","Happy Exploring 🤘"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSquareSquash%2Fweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSquareSquash%2Fweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSquareSquash%2Fweb/lists"}