From 8d9074a73368d9f3873271cf8ef4024f6b9521e9 Mon Sep 17 00:00:00 2001 From: jcass Date: Tue, 1 Mar 2016 07:40:15 +0200 Subject: [PATCH] Add tox environment configuration for linters. --- .csslintrc | 1 + .eslintrc | 11 +++ .gitignore | 1 + .travis.yml | 3 + README.rst | 29 ++++-- .../static/js/controls.js | 16 ++-- mopidy_musicbox_webclient/static/js/gui.js | 4 +- .../static/js/process_ws.js | 2 +- package.json | 33 +++++++ tidy.js | 88 +++++++++++++++++++ tox.ini | 36 +++++++- 11 files changed, 204 insertions(+), 20 deletions(-) create mode 100644 .csslintrc create mode 100644 .eslintrc create mode 100644 package.json create mode 100644 tidy.js diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 0000000..a271b01 --- /dev/null +++ b/.csslintrc @@ -0,0 +1 @@ +--format=compact diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..dc14e5b --- /dev/null +++ b/.eslintrc @@ -0,0 +1,11 @@ +{ + "extends": "standard", + "env": { + "jquery": true + }, + "rules": { + "indent": [2, 4, {"SwitchCase": 1}], + "no-undef": 0, // TODO: Set this to '2' once Javascript has been modularised. + "no-unused-vars": 0, // TODO: Set this to '2' once Javascript has been modularised. + } +} diff --git a/.gitignore b/.gitignore index 1b83512..b754965 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ docs/_build/ mopidy.log* node_modules/ nosetests.xml +npm-debug.log .project *.pbxproj *.egg-info diff --git a/.travis.yml b/.travis.yml index 637d177..5ce0d3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ python: env: - TOX_ENV=py27 - TOX_ENV=flake8 + - TOX_ENV=eslint + - TOX_ENV=csslint + - TOX_ENV=tidy install: - "pip install tox" diff --git a/README.rst b/README.rst index 1dc0007..1a9ca35 100644 --- a/README.rst +++ b/README.rst @@ -10,14 +10,26 @@ Mopidy-MusicBox-Webclient :target: https://pypi.python.org/pypi/Mopidy-MusicBox-Webclient/ :alt: Number of PyPI downloads -With Mopidy MusicBox Webclient, you can play your music on your computer (`Rapsberry Pi `_) +.. image:: https://img.shields.io/travis/pimusicbox/mopidy-musicbox-webclient/develop.svg?style=flat + :target: https://travis-ci.org/rectalogic/mopidy-pandora + :alt: Travis CI build status + +.. image:: https://img.shields.io/coveralls/pimusicbox/mopidy-musicbox-webclient/develop.svg?style=flat + :target: https://coveralls.io/r/rectalogic/mopidy-pandora?branch=develop + :alt: Test coverage + +.. image:: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat + :target: http://standardjs.com/ + :alt: JavaScript Standard Style + +With Mopidy MusicBox Webclient (MMW), you can play your music on your computer (`Rapsberry Pi `_) and remotely control it using your computer, tablet or phone. -This is a responsive webclient especially written for Mopidy, a music server. Responsive, so it works on desktop and -mobile browsers. You can browse, search and play albums, artists, playlists, and it has cover art from Last.fm. +This is a responsive webclient especially written for `Mopidy `_: a music server that can play +music from many different sources including Spotify, Google Music, SoundCloud, etc. or from your hard drive. The +webclient is responsive, so it works on desktop and mobile browsers. You can browse, search and play albums, artists, +playlists, and it has cover art from Last.fm. -`Mopidy `_ is a music server which can play music from Spotify, Google Music, SoundCloud, etc. -or from your hard drive. If you want to run Mopidy with this webclient on a Raspberry Pi, do yourself a favor and use my custom built SD-image: `Pi MusicBox `_. @@ -30,7 +42,7 @@ Installation Install by running:: - pip install Mopidy-MusicBox-Webclient + pip install mopidy-musicbox-webclient Alternatively, clone the repository and run ``sudo python setup.py install`` from within the project directory. e.g. :: @@ -58,6 +70,11 @@ Project resources Changelog ========= +v2.3.0 (UNRELEASED) +------------------- + +- Enhance build workflow to include style checks and syntax validation for HTML, CSS, and Javascript. + v2.2.0 (2016-03-01) ------------------- diff --git a/mopidy_musicbox_webclient/static/js/controls.js b/mopidy_musicbox_webclient/static/js/controls.js index 2638886..a7821bb 100644 --- a/mopidy_musicbox_webclient/static/js/controls.js +++ b/mopidy_musicbox_webclient/static/js/controls.js @@ -35,7 +35,7 @@ function playBrowsedTracks(action, trackIndex) { mopidy.playback.play({'tl_track': tlTracks[playIndex]}); } }; - + switch (action) { case PLAY_NOW: case PLAY_NEXT: @@ -65,7 +65,7 @@ function playTrack(action) { if (action == PLAY_NOW && divid == 'search') { action = PLAY_NOW_SEARCH; } - + $('#popupTracks').popup('close'); $('#controlspopup').popup('close'); toast('Loading...'); @@ -142,7 +142,7 @@ function playTrackByUri(track_uri, playlist_uri) { toast('Loading...'); mopidy.tracklist.add({'uris': [playlist_uri]}).then(function(tlTracks) { - // Can fail for all sorts of reasons. If so, just add individually. + // Can fail for all sorts of reasons. If so, just add individually. if (tlTracks.length === 0) { var trackUris = getTracksFromUri(playlist_uri, false); mopidy.tracklist.add({'uris': trackUris}).then(findAndPlayTrack); @@ -474,7 +474,7 @@ function playStreamUri(uri) { } function getCurrentlyPlaying() { - $('#streamuriinput').val(songdata.track.uri); + $('#streamuriinput').val(songdata.track.uri); var name = songdata.track.name; if (songdata.track.artists) { var artistStr = artistsToString(songdata.track.artists); @@ -482,7 +482,7 @@ function getCurrentlyPlaying() { name = artistStr + ' - ' + name; } } - $('#streamnameinput').val(name); + $('#streamnameinput').val(name); return true; } @@ -526,7 +526,7 @@ function getPlaylistFull(uri) { } function getFavourites() { - return getPlaylistByName(STREAMS_PLAYLIST_NAME, + return getPlaylistByName(STREAMS_PLAYLIST_NAME, STREAMS_PLAYLIST_SCHEME, true).then(function(playlist) { if (playlist) { @@ -593,7 +593,7 @@ function showFavourites() { return; } var tmp = ''; - + $.cookie.json = true; if ($.cookie('streamUris')) { tmp = ''; @@ -609,7 +609,7 @@ function showFavourites() { } } $('#streamuristable').html(tmp); - }); + }); } // TODO: Remove this upgrade path in next major release. diff --git a/mopidy_musicbox_webclient/static/js/gui.js b/mopidy_musicbox_webclient/static/js/gui.js index 827dc13..d1be849 100644 --- a/mopidy_musicbox_webclient/static/js/gui.js +++ b/mopidy_musicbox_webclient/static/js/gui.js @@ -235,7 +235,7 @@ function initSocketevents() { getPlaylists(); getUriSchemes().then(function() { showFavourites(); - }); + }); getBrowseDir(); getSearchSchemes(); showLoading(false); @@ -580,7 +580,7 @@ $(document).ready(function(event) { return true; } }); - + if ($(window).width() < 980) { $("#panel").panel("close"); diff --git a/mopidy_musicbox_webclient/static/js/process_ws.js b/mopidy_musicbox_webclient/static/js/process_ws.js index d8cfeeb..605a398 100644 --- a/mopidy_musicbox_webclient/static/js/process_ws.js +++ b/mopidy_musicbox_webclient/static/js/process_ws.js @@ -240,7 +240,7 @@ function processAlbumResults(resultArr) { return; } customTracklists[resultArr.uri] = resultArr; - + albumTracksToTable(resultArr, ALBUM_TABLE, resultArr.uri); var albumname = getAlbum(resultArr); var artistname = getArtist(resultArr); diff --git a/package.json b/package.json new file mode 100644 index 0000000..ee6c8e3 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "Mopidy-MusicBox-Webclient", + "version": "2.1.1", + "description": "Mopidy MusicBox web extension", + "main": "gui.js", + "directories": { + "test": "tests" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "eslint": "eslint mopidy_musicbox_webclient/static/js/**.js", + "csslint": "csslint mopidy_musicbox_webclient/static/css/**.css", + "tidy": "node tidy.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pimusicbox/mopidy-musicbox-webclient.git" + }, + "author": "Wouter van Wijk", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/pimusicbox/mopidy-musicbox-webclient/issues" + }, + "devDependencies": { + "eslint": "latest", + "eslint-config-standard": "latest", + "eslint-plugin-standard": "latest", + "eslint-plugin-promise": "latest", + "csslint": "latest", + "tidy-html5": "latest" + }, + "homepage": "https://github.com/pimusicbox/mopidy-musicbox-webclient#readme" +} diff --git a/tidy.js b/tidy.js new file mode 100644 index 0000000..bf857e0 --- /dev/null +++ b/tidy.js @@ -0,0 +1,88 @@ +var tidy = require('tidy-html5').tidy_html5 + +var fs = require('fs') + +// Traverse directory structure looking for 'html' or 'htm' files. +var getAllHtmlFilesFromFolder = function (dir) { + var filesystem = require('fs') + var results = [] + filesystem.readdirSync(dir).forEach(function (file) { + file = dir + '/' + file + var stat = filesystem.statSync(file) + + if (stat && stat.isDirectory()) { + results = results.concat(getAllHtmlFilesFromFolder(file)) + } else { + var extension = file.substr(file.lastIndexOf('.') + 1).toUpperCase() + if (extension === 'HTM' || extension === 'HTML') { + results.push(file) + } + } + }) + return results +} + +// Read file contents. +function readFiles (dirname, onFileContent) { + var filenames = getAllHtmlFilesFromFolder(dirname) + filenames.forEach(function (filename) { + fs.readFile(filename, 'utf-8', function (err, content) { + if (err) { + throw (err) + } + onFileContent(filename, content) + }) + }) +} + +var util = require('util') + +// Trap stderr output so that we can detect parsing errors. +function hook_stderr (callback) { + var old_write = process.stderr.write + + process.stderr.write = (function (write) { + return function (string, encoding, fd) { + write.apply(process.stdout, arguments) + callback(string, encoding, fd) + } + })(process.stderr.write) + + return function () { + process.stderr.write = old_write + } +} + +var unhook = hook_stderr(function (string, encoding, fd) { + if (string.indexOf('Error:') > 0) { + errors.push(string) + } +}) + +var errorsOccurred = false +var errors = [] + +// Exit with status 1 so that tox can detect errors. +process.on('exit', function () { + if (errorsOccurred === true) { + process.exit(1) + } +}) + +// Start linter +function processFiles (callback) { + console.log('Starting HTML linter...') + readFiles('mopidy_musicbox_webclient/static', function (filename, content) { + console.log('\n' + filename) + var result = tidy(content, {'quiet': true}) + if (errors.length > 0) { + console.error('\nHTML errors detected:\n' + errors.join('')) + errors = [] + errorsOccurred = true + } + }) +} + +processFiles(function () { + unhook() +}) diff --git a/tox.ini b/tox.ini index ead2ff1..96a5099 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, flake8 +envlist = py27, flake8, eslint, csslint, tidy [testenv] deps = @@ -13,11 +13,41 @@ commands = --basetemp={envtmpdir} \ --junit-xml=xunit-{envname}.xml \ --cov=mopidy_musicbox_webclient --cov-report=term-missing \ - {posargs} + {posargs:tests/} [testenv:flake8] deps = flake8 flake8-import-order skip_install = true -commands = flake8 +commands = flake8 {posargs:mopidy_musicbox_webclient} + +[testenv:eslint] +whitelist_externals = + /bin/bash +deps = + nodeenv +skip_install = true +commands = + - nodeenv --prebuilt {toxworkdir}/node_env + bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run eslint' + +[testenv:csslint] +whitelist_externals = + /bin/bash +deps = + nodeenv +skip_install = true +commands = + - nodeenv --prebuilt {toxworkdir}/node_env + bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run csslint' + +[testenv:tidy] +whitelist_externals = + /bin/bash +deps = + nodeenv +skip_install = true +commands = + - nodeenv --prebuilt {toxworkdir}/node_env + bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run tidy'