Bug 1507406 - ESLint: Enforce more strict import style (#4279)

Imports must now be grouped like so (with newlines between each):

```
// "external" modules
import _ from 'lodash';
import chalk from 'chalk';

// modules from a "parent" directory
import foo from '../foo';
import qux from '../../foo/qux';

// "sibling" modules from the same or a sibling's directory
import bar from './bar';
import baz from './bar/baz';
```

The `import/order` rule has auto-fix support, so any errors can be
resolved using `yarn lint --fix`.

See:
https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md
This commit is contained in:
Ed Morley 2018-11-16 08:07:49 +00:00 коммит произвёл GitHub
Родитель 4e3bcfa1a8
Коммит 4db0cfa973
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
49 изменённых файлов: 97 добавлений и 40 удалений

Просмотреть файл

@ -47,5 +47,13 @@ module.exports = {
'react/jsx-one-expression-per-line': 'off',
'react/jsx-wrap-multilines': 'off',
'react/no-access-state-in-setstate': 'off',
// Override AirBnB's config for this rule to make it more strict.
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md
'import/order': [
'error',
{
'newlines-between': 'always',
},
],
},
};

Просмотреть файл

@ -35,3 +35,8 @@ UI
--
We use the [Airbnb](https://github.com/airbnb/javascript) style guide for Javascript and validate it with ESlint (see Validating Javascript in the [Installation section](installation.html#validating-javascript)). For CSS, we use [reactstrap](https://reactstrap.github.io/) and Bootstrap's utility classes as much as possible before adding custom CSS to a style sheet. Any custom style that can be made reusable should be named generically and stored in the ``ui/css/treeherder-global.css`` file.
Imports in JS/JSX must be ordered like so (with newlines between each group):
1. external modules (eg `'react'`)
2. modules from a parent directory (eg `'../foo'`)
3. "sibling" modules from the same or a sibling's directory (eg `'./bar'` or './bar/baz')

Просмотреть файл

@ -1,4 +1,5 @@
import { OIDCCredentialAgent, Queue } from 'taskcluster-client-web';
import { tcRootUrl, getUserSessionUrl } from './url';
const taskcluster = (() => {

Просмотреть файл

@ -4,8 +4,9 @@ import { Link } from 'react-router-dom';
import Icon from 'react-fontawesome';
import ReactTable from 'react-table';
import { calculateMetrics, prettyDate, tableRowStyling } from './helpers';
import { bugDetailsEndpoint, getJobsUrl } from '../helpers/url';
import { calculateMetrics, prettyDate, tableRowStyling } from './helpers';
import BugLogColumn from './BugLogColumn';
import Layout from './Layout';
import withView from './View';

Просмотреть файл

@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tooltip } from 'reactstrap';
import { getLogViewerUrl } from '../helpers/url';

Просмотреть файл

@ -3,9 +3,9 @@ import 'react-day-picker/lib/style.css';
import DayPickerInput from 'react-day-picker/DayPickerInput';
import moment from 'moment';
import PropTypes from 'prop-types';
import { parseDate, formatDate } from 'react-day-picker/moment';
import { Button } from 'reactstrap';
import { ISODate } from './helpers';
export default class DateRangePicker extends React.Component {

Просмотреть файл

@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Alert } from 'reactstrap';
import { processErrorMessage } from './helpers';
const ErrorMessages = ({ failureMessage, failureStatus, errorMessages }) => {

Просмотреть файл

@ -3,11 +3,12 @@ import { Container } from 'reactstrap';
import PropTypes from 'prop-types';
import Icon from 'react-fontawesome';
import ErrorBoundary from '../shared/ErrorBoundary';
import Navigation from './Navigation';
import GraphsContainer from './GraphsContainer';
import ErrorMessages from './ErrorMessages';
import { prettyErrorMessages, errorMessageClass } from './constants';
import ErrorBoundary from '../shared/ErrorBoundary';
const Layout = (props) => {

Просмотреть файл

@ -4,9 +4,10 @@ import PropTypes from 'prop-types';
import moment from 'moment';
import ReactTable from 'react-table';
import { bugsEndpoint } from '../helpers/url';
import BugColumn from './BugColumn';
import { calculateMetrics, prettyDate, ISODate, tableRowStyling } from './helpers';
import { bugsEndpoint } from '../helpers/url';
import withView from './View';
import Layout from './Layout';
import DateRangePicker from './DateRangePicker';

Просмотреть файл

@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { updateQueryParams, validateQueryParams, mergeData, formatBugs } from './helpers';
import { graphsEndpoint, parseQueryParams, createQueryParams, createApiUrl,
bugzillaBugsApi } from '../helpers/url';
import { getData } from '../helpers/http';
import { updateQueryParams, validateQueryParams, mergeData, formatBugs } from './helpers';
const withView = defaultState => WrappedComponent =>
class View extends React.Component {
constructor(props) {

Просмотреть файл

@ -1,4 +1,5 @@
import moment from 'moment';
import { prettyErrorMessages } from './constants';
// be sure to wrap date arg in a moment()

Просмотреть файл

@ -3,24 +3,25 @@ import { hot } from 'react-hot-loader';
import SplitPane from 'react-split-pane';
import { thFavicons } from '../helpers/constants';
import { Pushes } from './context/Pushes';
import { SelectedJob } from './context/SelectedJob';
import { PinnedJobs } from './context/PinnedJobs';
import { Notifications } from '../shared/context/Notifications';
import NotificationList from '../shared/NotificationList';
import ShortcutTable from '../shared/ShortcutTable';
import { matchesDefaults } from '../helpers/filter';
import { getAllUrlParams, getRepo } from '../helpers/location';
import { deployedRevisionUrl } from '../helpers/url';
import ClassificationTypeModel from '../models/classificationType';
import FilterModel from '../models/filter';
import RepositoryModel from '../models/repository';
import { Pushes } from './context/Pushes';
import { SelectedJob } from './context/SelectedJob';
import { PinnedJobs } from './context/PinnedJobs';
import PrimaryNavBar from './headerbars/PrimaryNavBar';
import ActiveFilters from './headerbars/ActiveFilters';
import UpdateAvailable from './headerbars/UpdateAvailable';
import DetailsPanel from './details/DetailsPanel';
import PushList from './pushes/PushList';
import KeyboardShortcuts from './KeyboardShortcuts';
import NotificationList from '../shared/NotificationList';
import ShortcutTable from '../shared/ShortcutTable';
const DEFAULT_DETAILS_PCT = 40;
const REVISION_POLL_INTERVAL = 1000 * 60 * 5;

Просмотреть файл

@ -11,9 +11,10 @@ import {
import { formatTaskclusterError } from '../helpers/errorMessage';
import TaskclusterModel from '../models/taskcluster';
import { withPushes } from './context/Pushes';
import { withNotifications } from '../shared/context/Notifications';
import { withPushes } from './context/Pushes';
class CustomJobActions extends React.PureComponent {
constructor(props) {
super(props);

Просмотреть файл

@ -3,9 +3,10 @@ import PropTypes from 'prop-types';
import { HotKeys } from 'react-hotkeys';
import { thEvents } from '../helpers/constants';
import { withNotifications } from '../shared/context/Notifications';
import { withPinnedJobs } from './context/PinnedJobs';
import { withSelectedJob } from './context/SelectedJob';
import { withNotifications } from '../shared/context/Notifications';
const keyMap = {
addRelatedBug: 'b',

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withNotifications } from '../../shared/context/Notifications';
const COUNT_ERROR = 'Max pinboard size of 500 reached.';

Просмотреть файл

@ -15,9 +15,10 @@ import { getUrlParam, setUrlParam } from '../../helpers/location';
import { getJobsUrl } from '../../helpers/url';
import JobModel from '../../models/job';
import PushModel from '../../models/push';
import { withNotifications } from '../../shared/context/Notifications';
import { withPinnedJobs } from './PinnedJobs';
import { withPushes } from './Pushes';
import { withNotifications } from '../../shared/context/Notifications';
const SelectedJobContext = React.createContext({});

Просмотреть файл

@ -5,6 +5,7 @@ import chunk from 'lodash/chunk';
import { thEvents, thBugSuggestionLimit } from '../../helpers/constants';
import { withPinnedJobs } from '../context/PinnedJobs';
import { withSelectedJob } from '../context/SelectedJob';
import { withPushes } from '../context/Pushes';
import { getLogViewerUrl, getReftestUrl } from '../../helpers/url';
import BugJobMapModel from '../../models/bugJobMap';
import BugSuggestionsModel from '../../models/bugSuggestions';
@ -14,10 +15,10 @@ import JobDetailModel from '../../models/jobDetail';
import JobLogUrlModel from '../../models/jobLogUrl';
import TextLogStepModel from '../../models/textLogStep';
import PerfSeriesModel from '../../models/perfSeries';
import PinBoard from './PinBoard';
import SummaryPanel from './summary/SummaryPanel';
import TabsPanel from './tabs/TabsPanel';
import { withPushes } from '../context/Pushes';
export const pinboardHeight = 100;

Просмотреть файл

@ -9,12 +9,13 @@ import { getInspectTaskUrl, getReftestUrl } from '../../../helpers/url';
import JobModel from '../../../models/job';
import TaskclusterModel from '../../../models/taskcluster';
import CustomJobActions from '../../CustomJobActions';
import LogUrls from './LogUrls';
import { withSelectedJob } from '../../context/SelectedJob';
import { withPinnedJobs } from '../../context/PinnedJobs';
import { withPushes } from '../../context/Pushes';
import { withNotifications } from '../../../shared/context/Notifications';
import LogUrls from './LogUrls';
class ActionBar extends React.PureComponent {
constructor(props) {
super(props);

Просмотреть файл

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { withSelectedJob } from '../../context/SelectedJob';
import JobInfo from '../../../shared/JobInfo';
import ActionBar from './ActionBar';
import ClassificationsPanel from './ClassificationsPanel';
import StatusPanel from './StatusPanel';

Просмотреть файл

@ -5,15 +5,15 @@ import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import { thEvents } from '../../../helpers/constants';
import { getAllUrlParams } from '../../../helpers/location';
import { getStatus } from '../../../helpers/job';
import JobDetails from '../../../shared/JobDetails';
import { withPinnedJobs } from '../../context/PinnedJobs';
import { withSelectedJob } from '../../context/SelectedJob';
import FailureSummaryTab from './failureSummary/FailureSummaryTab';
import PerformanceTab from './PerformanceTab';
import AutoclassifyTab from './autoclassify/AutoclassifyTab';
import AnnotationsTab from './AnnotationsTab';
import SimilarJobsTab from './SimilarJobsTab';
import { withPinnedJobs } from '../../context/PinnedJobs';
import { withSelectedJob } from '../../context/SelectedJob';
class TabsPanel extends React.Component {
constructor(props) {

Просмотреть файл

@ -5,13 +5,13 @@ import React from 'react';
import { thEvents } from '../../../../helpers/constants';
import { getProjectJobUrl } from '../../../../helpers/url';
import TextLogErrorsModel from '../../../../models/textLogErrors';
import { withSelectedJob } from '../../../context/SelectedJob';
import { withPinnedJobs } from '../../../context/PinnedJobs';
import { withNotifications } from '../../../../shared/context/Notifications';
import AutoclassifyToolbar from './AutoclassifyToolbar';
import ErrorLine from './ErrorLine';
import ErrorLineData from './ErrorLineModel';
import { withSelectedJob } from '../../../context/SelectedJob';
import { withPinnedJobs } from '../../../context/PinnedJobs';
import { withNotifications } from '../../../../shared/context/Notifications';
class AutoclassifyTab extends React.Component {
constructor(props) {

Просмотреть файл

@ -5,11 +5,11 @@ import { FormGroup } from 'reactstrap';
import { thEvents } from '../../../../helpers/constants';
import { stringOverlap, highlightLogLine } from '../../../../helpers/autoclassify';
import { getBugUrl, getLogViewerUrl } from '../../../../helpers/url';
import { withSelectedJob } from '../../../context/SelectedJob';
import LineOption from './LineOption';
import LineOptionModel from './LineOptionModel';
import StaticLineOption from './StaticLineOption';
import { withSelectedJob } from '../../../context/SelectedJob';
const GOOD_MATCH_SCORE = 0.75;
const BAD_MATCH_SCORE = 0.25;

Просмотреть файл

@ -4,13 +4,13 @@ import PropTypes from 'prop-types';
import { thEvents } from '../../../../helpers/constants';
import { isReftest } from '../../../../helpers/job';
import { getBugUrl } from '../../../../helpers/url';
import { withSelectedJob } from '../../../context/SelectedJob';
import { withPinnedJobs } from '../../../context/PinnedJobs';
import BugFiler from '../../BugFiler';
import ErrorsList from './ErrorsList';
import ListItem from './ListItem';
import SuggestionsListItem from './SuggestionsListItem';
import BugFiler from '../../BugFiler';
import { withSelectedJob } from '../../../context/SelectedJob';
import { withPinnedJobs } from '../../../context/PinnedJobs';
class FailureSummaryTab extends React.Component {
constructor(props) {

Просмотреть файл

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { thBugSuggestionLimit } from '../../../../helpers/constants';
import BugListItem from './BugListItem';
export default class SuggestionsListItem extends React.Component {

Просмотреть файл

@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import Logo from '../../img/treeherder-logo.png';
import Login from '../../shared/auth/Login';
import LogoMenu from '../../shared/LogoMenu';
import NotificationsMenu from './NotificationsMenu';
import InfraMenu from './InfraMenu';
import ReposMenu from './ReposMenu';

Просмотреть файл

@ -10,9 +10,10 @@ import {
} from '../../helpers/location';
import RepositoryModel from '../../models/repository';
import ErrorBoundary from '../../shared/ErrorBoundary';
import WatchedRepo from './WatchedRepo';
import { withPushes } from '../context/Pushes';
import WatchedRepo from './WatchedRepo';
const MAX_WATCHED_REPOS = 3;
const WATCHED_REPOS_STORAGE_KEY = 'thWatchedRepos';

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getBtnClass, findJobInstance } from '../../helpers/job';
import { getUrlParam } from '../../helpers/location';

Просмотреть файл

@ -6,6 +6,7 @@ import { withSelectedJob } from '../context/SelectedJob';
import { thFailureResults } from '../../helpers/constants';
import { getBtnClass, getStatus } from '../../helpers/job';
import { getUrlParam } from '../../helpers/location';
import JobButton from './JobButton';
import JobCount from './JobCount';

Просмотреть файл

@ -1,8 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import { getStatus } from '../../helpers/job';
import JobButton from './JobButton';
import JobGroup from './JobGroup';
import { getStatus } from '../../helpers/job';
export default class JobsAndGroups extends React.Component {
render() {

Просмотреть файл

@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import JobsAndGroups from './JobsAndGroups';
function PlatformName(props) {

Просмотреть файл

@ -2,9 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import sortBy from 'lodash/sortBy';
import PushJobs from './PushJobs';
import PushHeader from './PushHeader';
import { RevisionList } from './RevisionList';
import { thEvents, thOptionOrder, thPlatformMap } from '../../helpers/constants';
import { withPushes } from '../context/Pushes';
import { escapeId, getGroupMapKey } from '../../helpers/aggregateId';
@ -15,6 +12,10 @@ import { withNotifications } from '../../shared/context/Notifications';
import { getRevisionTitle } from '../../helpers/revision';
import { getPercentComplete } from '../../helpers/display';
import PushHeader from './PushHeader';
import PushJobs from './PushJobs';
import { RevisionList } from './RevisionList';
const watchCycleStates = ['none', 'push', 'job', 'none'];
const platformArray = Object.values(thPlatformMap);

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getUrlParam } from '../../helpers/location';
import { formatTaskclusterError } from '../../helpers/errorMessage';
import CustomJobActions from '../CustomJobActions';

Просмотреть файл

@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import PushActionMenu from './PushActionMenu';
import { getPercentComplete, toDateStr } from '../../helpers/display';
import { formatTaskclusterError } from '../../helpers/errorMessage';
import { getJobsUrl } from '../../helpers/url';
@ -11,6 +11,8 @@ import { withSelectedJob } from '../context/SelectedJob';
import { withPushes } from '../context/Pushes';
import { withNotifications } from '../../shared/context/Notifications';
import PushActionMenu from './PushActionMenu';
// url params we don't want added from the current querystring to the revision
// and author links.
const SKIPPED_LINK_PARAMS = [

Просмотреть файл

@ -9,9 +9,10 @@ import { findInstance, findSelectedInstance } from '../../helpers/job';
import { getUrlParam } from '../../helpers/location';
import { getLogViewerUrl } from '../../helpers/url';
import JobModel from '../../models/job';
import Platform from './Platform';
import { withPushes } from '../context/Pushes';
import Platform from './Platform';
class PushJobs extends React.Component {
static getDerivedStateFromProps(nextProps) {
const { filterModel, push, platforms, runnableVisible } = nextProps;

Просмотреть файл

@ -2,9 +2,10 @@ import React from 'react';
import PropTypes from 'prop-types';
import ErrorBoundary from '../../shared/ErrorBoundary';
import { withPushes } from '../context/Pushes';
import Push from './Push';
import PushLoadErrors from './PushLoadErrors';
import { withPushes } from '../context/Pushes';
class PushList extends React.Component {
constructor(props) {

Просмотреть файл

@ -2,9 +2,10 @@
/* eslint-disable func-names, prefer-arrow-callback */
import numeral from 'numeral';
import treeherder from './treeherder';
import { getJobsUrl } from '../helpers/url';
import treeherder from './treeherder';
treeherder.filter('getRevisionUrl', function () {
return function (revision, projectName) {
if (revision) {

Просмотреть файл

@ -7,6 +7,7 @@ import LocalStorageModule from 'angular-local-storage';
import { react2angular } from 'react2angular/index.es2015';
import Login from '../shared/auth/Login';
import treeherderModule from './treeherder';
const perf = angular.module('perf', [

Просмотреть файл

@ -1,6 +1,5 @@
// Remove the eslint-disable when rewriting this file during the React conversion.
/* eslint-disable func-names, prefer-arrow-callback */
import perf from './perf';
import alertsCtrlTemplate from '../partials/perf/alertsctrl.html';
import graphsCtrlTemplate from '../partials/perf/graphsctrl.html';
import compareCtrlTemplate from '../partials/perf/comparectrl.html';
@ -10,6 +9,8 @@ import compareSubtestDistributionTemplate from '../partials/perf/comparesubtestd
import helpMenuTemplate from '../partials/perf/helpMenu.html';
import tooltipGraphsTemplate from '../partials/perf/tooltipgraphs.html';
import perf from './perf';
// configure the router here, after we have defined all the controllers etc
perf.config(['$compileProvider', '$locationProvider', '$httpProvider', '$stateProvider', '$urlRouterProvider',
function ($compileProvider, $locationProvider, $httpProvider, $stateProvider, $urlRouterProvider) {

Просмотреть файл

@ -12,6 +12,7 @@ import PushModel from '../models/push';
import TextLogStepModel from '../models/textLogStep';
import JobDetails from '../shared/JobDetails';
import JobInfo from '../shared/JobInfo';
import Navigation from './Navigation';
import ErrorLines from './ErrorLines';

Просмотреть файл

@ -1,6 +1,7 @@
import { thPlatformMap } from '../helpers/constants';
import { createQueryParams, getProjectUrl } from '../helpers/url';
import { formatTaskclusterError } from '../helpers/errorMessage';
import TaskclusterModel from './taskcluster';
const uri = getProjectUrl('/jobs/');

Просмотреть файл

@ -1,6 +1,7 @@
import queryString from 'query-string';
import { getApiUrl, getProjectUrl } from '../helpers/url';
import OptionCollectionModel from './optionCollection';
export const getTestName = function getTestName(signatureProps) {

Просмотреть файл

@ -4,6 +4,7 @@ import { thMaxPushFetchSize } from '../helpers/constants';
import { getUrlParam } from '../helpers/location';
import taskcluster from '../helpers/taskcluster';
import { createQueryParams, getProjectUrl } from '../helpers/url';
import JobModel from './job';
import TaskclusterModel from './taskcluster';

Просмотреть файл

@ -1,4 +1,5 @@
import { getProjectUrl } from '../helpers/url';
import JobModel from './job';
const uri = getProjectUrl('/runnable_jobs/');

Просмотреть файл

@ -1,11 +1,12 @@
import chunk from 'lodash/chunk';
import { tValueCareMin, tValueConfidence } from './constants';
import { getApiUrl, createQueryParams } from '../helpers/url';
import { getData } from '../helpers/http';
import PerfSeriesModel from '../models/perfSeries';
import { phTimeRanges } from '../helpers/constants';
import { tValueCareMin, tValueConfidence } from './constants';
export const calcPercentOf = function calcPercentOf(a, b) {
return b ? 100 * a / b : 0;
};

Просмотреть файл

@ -2,13 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import isEqual from 'lodash/isEqual';
import AuthService from './AuthService';
import { loggedOutUser } from '../../helpers/auth';
import taskcluster from '../../helpers/taskcluster';
import { getApiUrl, loginCallbackUrl } from '../../helpers/url';
import UserModel from '../../models/user';
import { withNotifications } from '../context/Notifications';
import AuthService from './AuthService';
/**
* This component handles logging in to Taskcluster Authentication
*

Просмотреть файл

@ -6,10 +6,12 @@ import {
} from 'redux';
import createHistory from 'history/createBrowserHistory';
import createDebounce from 'redux-debounce';
import * as groupsStore from './modules/groups';
import { thPlatformMap } from '../../helpers/constants';
import { getServiceUrl, getProjectUrl } from '../../helpers/url';
import * as groupsStore from './modules/groups';
function getGroupText(group) {
const symbol = group.symbol.startsWith('tc-') ?
group.symbol.substring(3) : group.symbol;

Просмотреть файл

@ -4,10 +4,11 @@ import { Form, FormGroup, Input, Label, Row, Col, Table, Container } from 'react
import Icon from 'react-fontawesome';
import { connect } from 'react-redux';
import { store, actions } from '../redux/store';
import { Test, BugCount } from './Test';
import StatusProgress from './StatusProgress';
import StatusNavbar from './StatusNavbar';
import { store, actions } from '../redux/store';
const mapStateToProps = ({ groups }) => groups;

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react';
import { Nav, Navbar, Collapse } from 'reactstrap';
import logoUrl from '../../img/treeherder-logo.png';
export default class Navigation extends React.Component {

Просмотреть файл

@ -7,9 +7,9 @@ import { Badge } from 'reactstrap';
import { store, actions } from '../redux/store';
import { thPlatformMap } from '../../helpers/constants';
import LogViewer from './LogViewer';
import { getBugUrl } from '../../helpers/url';
import LogViewer from './LogViewer';
const mapStateToProps = ({ groups }) => ({
expanded: groups.expanded,