Add --exclude-unknown-project arg and corresponding config

This commit is contained in:
Alan Hamlett 2018-04-15 13:13:33 -07:00
parent f2b8776e21
commit 3e47f77f47
11 changed files with 118 additions and 18 deletions

View file

@ -0,0 +1,4 @@
[settings]
debug = false
api_key = 1090a6ae-855f-4be7-b8fb-3edbaf1aa3ec
exclude_unknown_project = true

View file

@ -15,5 +15,6 @@ no_ssl_verify = false
timeout = abc timeout = abc
api_url = https://localhost:0/api/v1/heartbeats api_url = https://localhost:0/api/v1/heartbeats
hostname = fromcfgfile hostname = fromcfgfile
exclude_unknown_project = false
[git] [git]
submodules_disabled = submodules_disabled =

View file

@ -4,8 +4,8 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-filenames]
[--exclude EXCLUDE] [--include INCLUDE] [--exclude EXCLUDE] [--exclude-unknown-project]
[--include-only-with-project-file] [--extra-heartbeats] [--include INCLUDE] [--include-only-with-project-file]
[--log-file LOG_FILE] [--api-url API_URL] [--timeout TIMEOUT] [--extra-heartbeats] [--log-file LOG_FILE] [--api-url API_URL]
[--config CONFIG] [--verbose] [--version] [--timeout TIMEOUT] [--config CONFIG] [--verbose] [--version]
wakatime: error: Missing api key. Find your api key from wakatime.com/settings/api-key. wakatime: error: Missing api key. Find your api key from wakatime.com/settings/api-key.

View file

@ -4,8 +4,8 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-filenames]
[--exclude EXCLUDE] [--include INCLUDE] [--exclude EXCLUDE] [--exclude-unknown-project]
[--include-only-with-project-file] [--extra-heartbeats] [--include INCLUDE] [--include-only-with-project-file]
[--log-file LOG_FILE] [--api-url API_URL] [--timeout TIMEOUT] [--extra-heartbeats] [--log-file LOG_FILE] [--api-url API_URL]
[--config CONFIG] [--verbose] [--version] [--timeout TIMEOUT] [--config CONFIG] [--verbose] [--version]
wakatime: error: Missing api key. Find your api key from wakatime.com/settings/api-key. wakatime: error: Missing api key. Find your api key from wakatime.com/settings/api-key.

View file

@ -4,8 +4,8 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-filenames]
[--exclude EXCLUDE] [--include INCLUDE] [--exclude EXCLUDE] [--exclude-unknown-project]
[--include-only-with-project-file] [--extra-heartbeats] [--include INCLUDE] [--include-only-with-project-file]
[--log-file LOG_FILE] [--api-url API_URL] [--timeout TIMEOUT] [--extra-heartbeats] [--log-file LOG_FILE] [--api-url API_URL]
[--config CONFIG] [--verbose] [--version] [--timeout TIMEOUT] [--config CONFIG] [--verbose] [--version]
wakatime: error: argument --timeout: invalid int value: 'abc' wakatime: error: argument --timeout: invalid int value: 'abc'

View file

@ -4,10 +4,10 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-filenames]
[--exclude EXCLUDE] [--include INCLUDE] [--exclude EXCLUDE] [--exclude-unknown-project]
[--include-only-with-project-file] [--extra-heartbeats] [--include INCLUDE] [--include-only-with-project-file]
[--log-file LOG_FILE] [--api-url API_URL] [--timeout TIMEOUT] [--extra-heartbeats] [--log-file LOG_FILE] [--api-url API_URL]
[--config CONFIG] [--verbose] [--version] [--timeout TIMEOUT] [--config CONFIG] [--verbose] [--version]
Common interface for the WakaTime api. Common interface for the WakaTime api.
@ -51,6 +51,9 @@ optional arguments:
--hide-filenames Obfuscate filenames. Will not send file names to api. --hide-filenames Obfuscate filenames. Will not send file names to api.
--exclude EXCLUDE Filename patterns to exclude from logging. POSIX regex --exclude EXCLUDE Filename patterns to exclude from logging. POSIX regex
syntax. Can be used more than once. syntax. Can be used more than once.
--exclude-unknown-project
When set, any activity where the project cannot be
detected will be ignored.
--include INCLUDE Filename patterns to log. When used in combination --include INCLUDE Filename patterns to log. When used in combination
with --exclude, files matching include will still be with --exclude, files matching include will still be
logged. POSIX regex syntax. Can be used more than logged. POSIX regex syntax. Can be used more than

View file

@ -1026,6 +1026,34 @@ class ArgumentsTestCase(TestCase):
self.assertOfflineHeartbeatsSynced() self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
@log_capture()
def test_exclude_unknown_project_arg(self, logs):
logging.disable(logging.NOTSET)
response = Response()
response.status_code = 0
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt'))
config = 'tests/samples/configs/good_config.cfg'
args = ['--file', entity, '--config', config, '--exclude-unknown-project', '--verbose', '--log-file', '~/.wakatime.log']
retval = execute(args)
self.assertEquals(retval, SUCCESS)
self.assertNothingPrinted()
actual = self.getLogOutput(logs)
expected = 'WakaTime DEBUG Skipping because project unknown.'
self.assertEquals(actual, expected)
self.assertHeartbeatNotSent()
self.assertHeartbeatNotSavedOffline()
self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheUntouched()
@log_capture() @log_capture()
def test_uses_wakatime_home_env_variable(self, logs): def test_uses_wakatime_home_env_variable(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)

View file

@ -515,6 +515,34 @@ class ConfigsTestCase(TestCase):
self.assertOfflineHeartbeatsSynced() self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheUntouched() self.assertSessionCacheUntouched()
@log_capture()
def test_exclude_file_because_project_unknown(self, logs):
logging.disable(logging.NOTSET)
response = Response()
response.status_code = 0
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt'))
config = 'tests/samples/configs/exclude_unknown_project.cfg'
args = ['--file', entity, '--config', config, '--verbose', '--log-file', '~/.wakatime.log']
retval = execute(args)
self.assertEquals(retval, SUCCESS)
self.assertNothingPrinted()
actual = self.getLogOutput(logs)
expected = 'WakaTime DEBUG Skipping because project unknown.'
self.assertEquals(actual, expected)
self.assertHeartbeatNotSent()
self.assertHeartbeatNotSavedOffline()
self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheUntouched()
@log_capture() @log_capture()
def test_include_file_with_project_file(self, logs): def test_include_file_with_project_file(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)

View file

@ -17,7 +17,7 @@ from wakatime.constants import API_ERROR, SUCCESS
from wakatime.exceptions import NotYetImplemented from wakatime.exceptions import NotYetImplemented
from wakatime.projects.base import BaseProject from wakatime.projects.base import BaseProject
from wakatime.projects.git import Git from wakatime.projects.git import Git
from .utils import ANY, DynamicIterable, TestCase, CustomResponse, mock, json from .utils import ANY, DynamicIterable, TestCase, TemporaryDirectory, CustomResponse, mock, json
class ProjectTestCase(TestCase): class ProjectTestCase(TestCase):
@ -630,3 +630,24 @@ class ProjectTestCase(TestCase):
self.assertNothingPrinted() self.assertNothingPrinted()
self.assertNothingLogged(logs) self.assertNothingLogged(logs)
@log_capture()
def test_exclude_unknown_project_when_project_detected(self, logs):
logging.disable(logging.NOTSET)
response = Response()
response.status_code = 0
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt'))
config = 'tests/samples/configs/exclude_unknown_project.cfg'
args = ['--file', entity, '--project', 'proj-arg', '--config', config, '--log-file', '~/.wakatime.log']
execute(args)
self.assertNothingPrinted()
self.assertNothingLogged(logs)
self.assertEquals('proj-arg', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])

View file

@ -136,6 +136,10 @@ def parse_arguments():
parser.add_argument('--exclude', dest='exclude', action='append', parser.add_argument('--exclude', dest='exclude', action='append',
help='Filename patterns to exclude from logging. ' + help='Filename patterns to exclude from logging. ' +
'POSIX regex syntax. Can be used more than once.') 'POSIX regex syntax. Can be used more than once.')
parser.add_argument('--exclude-unknown-project',
dest='exclude_unknown_project', action='store_true',
help='When set, any activity where the project ' +
'cannot be detected will be ignored.')
parser.add_argument('--include', dest='include', action='append', parser.add_argument('--include', dest='include', action='append',
help='Filename patterns to log. When used in ' + help='Filename patterns to log. When used in ' +
'combination with --exclude, files matching ' + 'combination with --exclude, files matching ' +
@ -144,7 +148,7 @@ def parse_arguments():
parser.add_argument('--include-only-with-project-file', parser.add_argument('--include-only-with-project-file',
dest='include_only_with_project_file', dest='include_only_with_project_file',
action='store_true', action='store_true',
help='Disables tracking folders unless they contain '+ help='Disables tracking folders unless they contain ' +
'a .wakatime-project file. Defaults to false.') 'a .wakatime-project file. Defaults to false.')
parser.add_argument('--ignore', dest='ignore', action='append', parser.add_argument('--ignore', dest='ignore', action='append',
help=argparse.SUPPRESS) help=argparse.SUPPRESS)
@ -243,6 +247,8 @@ def parse_arguments():
args.include.append(pattern) args.include.append(pattern)
except TypeError: # pragma: nocover except TypeError: # pragma: nocover
pass pass
if not args.exclude_unknown_project and configs.has_option('settings', 'exclude_unknown_project'):
args.exclude_unknown_project = configs.getboolean('settings', 'exclude_unknown_project')
if not args.hide_filenames and args.hidefilenames: if not args.hide_filenames and args.hidefilenames:
args.hide_filenames = args.hidefilenames args.hide_filenames = args.hidefilenames
if args.hide_filenames: if args.hide_filenames:

View file

@ -94,6 +94,10 @@ class Heartbeat(object):
self.project = project self.project = project
self.branch = branch self.branch = branch
if self._excluded_by_unknown_project():
self.skip = u('Skipping because project unknown.')
return
try: try:
stats = get_file_stats(self.entity, stats = get_file_stats(self.entity,
entity_type=self.type, entity_type=self.type,
@ -210,6 +214,11 @@ class Heartbeat(object):
def _excluded_by_pattern(self): def _excluded_by_pattern(self):
return should_exclude(self.entity, self.args.include, self.args.exclude) return should_exclude(self.entity, self.args.include, self.args.exclude)
def _excluded_by_unknown_project(self):
if self.project:
return False
return self.args.exclude_unknown_project
def _excluded_by_missing_project_file(self): def _excluded_by_missing_project_file(self):
if not self.args.include_only_with_project_file: if not self.args.include_only_with_project_file:
return False return False