Merge "update_bug.py: Check project along with series"
diff --git a/.gitignore b/.gitignore
index d1c5cdb..305a3af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 .tox
+.nox
 build/*
 *.pyc
 jeepyb/versioninfo
diff --git a/.zuul.yaml b/.zuul.yaml
index 6107d2f..0e78370 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -2,8 +2,8 @@
     check:
       jobs:
         - gerritlib-jeepyb-integration
-        - tox-pep8
+        - nox-linters
     gate:
       jobs:
         - gerritlib-jeepyb-integration
-        - tox-pep8
+        - nox-linters
diff --git a/jeepyb/cmd/manage_projects.py b/jeepyb/cmd/manage_projects.py
index 212d899..1a93709 100644
--- a/jeepyb/cmd/manage_projects.py
+++ b/jeepyb/cmd/manage_projects.py
@@ -179,7 +179,13 @@
     if status != 0:
         log.error("Failed to push config for project: %s" % project)
         log.error(out)
-        return False
+        if 'project state does not permit write' in out:
+            # We tried to push an acl update to a read only project.
+            # This is an error to Gerrit, but we treat it as success
+            # to allow other acls to update.
+            return True
+        else:
+            return False
     return True
 
 
@@ -377,8 +383,10 @@
             # nothing was copied, so we're done
             return
         create_groups_file(project, gerrit, repo_path)
-        push_acl_config(project, remote_url, repo_path,
-                        GERRIT_GITID, ssh_env)
+        rc = push_acl_config(project, remote_url, repo_path,
+                             GERRIT_GITID, ssh_env)
+        if not rc:
+            raise Exception("Non zero acl push return value.")
     except Exception:
         log.exception(
             "Exception processing ACLS for %s." % project)
diff --git a/noxfile.py b/noxfile.py
new file mode 100644
index 0000000..c6a7079
--- /dev/null
+++ b/noxfile.py
@@ -0,0 +1,34 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.  You may obtain
+# a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import nox
+
+
+nox.options.error_on_external_run = True
+nox.options.reuse_existing_virtualenvs = True
+nox.options.sessions = ["linters"]
+
+
+@nox.session(python="3")
+def linters(session):
+    session.install("-r", "requirements.txt")
+    session.install("-r", "test-requirements.txt")
+    session.install(".")
+    session.run("flake8")
+
+
+@nox.session(python="3")
+def venv(session):
+    session.install("-r", "requirements.txt")
+    session.install("-r", "test-requirements.txt")
+    session.install(".")
+    session.run(*session.posargs)
diff --git a/setup.cfg b/setup.cfg
index 73ab438..e14db8b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -32,3 +32,10 @@
     update-blueprint = jeepyb.cmd.update_blueprint:main
     update-bug = jeepyb.cmd.update_bug:main
     welcome-message = jeepyb.cmd.welcome_message:main
+
+[flake8]
+# E125 and H are intentionally ignored
+# W503 is a mistake in flake8
+ignore = E125,H,W503,W504
+show-source = True
+exclude = .venv,.tox,.nox,dist,doc,build,*.egg
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 46bd1ce..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[tox]
-envlist = pep8
-
-[testenv]
-setenv = VIRTUAL_ENV={envdir}
-deps = -r{toxinidir}/requirements.txt
-       -r{toxinidir}/test-requirements.txt
-basepython = python3
-
-[testenv:pep8]
-commands = flake8
-
-[testenv:pyflakes]
-commands = flake8
-
-[testenv:venv]
-commands = {posargs}
-
-[flake8]
-# E125 and H are intentionally ignored
-# W503 is a mistake in flake8
-ignore = E125,H,W503,W504
-show-source = True
-exclude = .venv,.tox,dist,doc,build,*.egg