Skip to content

Commit 60a7772

Browse files
authored
Merge pull request #51 from BapRx/feat/exclude-paths-based-on-regex
chore(repo/find): Exlude paths based on regex
2 parents 9b4ed28 + 1262ec5 commit 60a7772

26 files changed

+204
-128
lines changed

Justfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ clean:
1313

1414
fmt:
1515
cargo fmt
16+
git ls-files | grep '\.py$' | xargs isort
1617
git ls-files | grep '\.py$' | xargs black
1718
git ls-files | grep '\.sh$' | xargs -L 1 shfmt --indent 4 --write
1819

@@ -23,6 +24,7 @@ fmt-check:
2324

2425
lint:
2526
cargo clippy --no-deps -- -Dwarnings
27+
git ls-files | grep '\.py$' | xargs ruff --ignore E501
2628
git ls-files | grep '\.sh$' | xargs -L 1 shellcheck --norc
2729

2830
lint-fix:

depcheck/update-cargo-dependencies.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
#!/usr/bin/env python3
22

3-
import subprocess
4-
import os
53
import json
6-
import sys
4+
import os
5+
import subprocess
76

87
import semver
98
import tomlkit

docs/src/developing.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ You will need the following tools:
3434
[here](https://github.com/casey/just#installation) for installation
3535
instructions (it's most likely just a simple `cargo install just`).
3636
* Docker & docker-compose for the e2e tests
37-
* `black` and `shfmt` for formatting.
38-
* `shellcheck` for shell script linting
37+
* `isort`, `black` and `shfmt` for formatting.
38+
* `ruff` and `shellcheck` for linting.
3939
* `mdbook` for the documentation
4040

4141
Here are the tools:

docs/src/local_configuration.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Let's try it out:
1111
## Get the example configuration
1212

1313
```bash
14-
$ curl --proto '=https' --tlsv1.2 -sSfO https://raw.githubusercontent.com/hakoerber/git-repo-manager/master/example.config.toml
14+
curl --proto '=https' --tlsv1.2 -sSfO https://raw.githubusercontent.com/hakoerber/git-repo-manager/master/example.config.toml
1515
```
1616

1717
Then, you're ready to run the first sync. This will clone all configured
@@ -30,7 +30,7 @@ $ grm repos sync config --config example.config.toml
3030

3131
If you run it again, it will report no changes:
3232

33-
```
33+
```bash
3434
$ grm repos sync config -c example.config.toml
3535
[✔] git-repo-manager: OK
3636
[✔] dotfiles: OK
@@ -43,11 +43,18 @@ write a configuration from scratch. Luckily, GRM has a way to generate a
4343
configuration from an existing file tree:
4444

4545
```bash
46-
$ grm repos find local ~/your/project/root > config.toml
46+
grm repos find local ~/your/project/root > config.toml
4747
```
4848

4949
This will detect all repositories and remotes and write them to `config.toml`.
5050

51+
You can exclude repositories from the generated configuration by providing
52+
a regex that will be test against the path of each discovered repository:
53+
54+
```bash
55+
grm repos find local ~/your/project/root --exclude "^.*/subdir/match-(foo|bar)/.*$" > config.toml
56+
```
57+
5158
### Show the state of your projects
5259

5360
```bash
@@ -65,7 +72,7 @@ $ grm repos status --config example.config.toml
6572
You can also use `status` without `--config` to check the repository you're
6673
currently in:
6774

68-
```
75+
```bash
6976
$ cd ~/example-projects/dotfiles
7077
$ grm repos status
7178
╭──────────┬──────────┬────────┬──────────┬───────┬─────────╮
@@ -79,5 +86,5 @@ $ grm repos status
7986

8087
By default, the repo configuration uses TOML. If you prefer YAML, just give it a
8188
YAML file instead (file ending does not matter, `grm` will figure out the
82-
format). For generating a configuration, pass `--format yaml` to `grm repo
89+
format). For generating a configuration, pass `--format yaml` to `grm repo
8390
find` which generates a YAML configuration instead of a TOML configuration.

docs/src/testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Note: You will most likely not need to read this.
4949
Each test parameter will exponentially increase the number of tests that will be
5050
run. As a general rule, comprehensiveness is more important than test suite
5151
runtime (so if in doubt, better to add another parameter to catch every edge
52-
case). But try to keep the total runtime sane. Currently, the whole `just e2e`
52+
case). But try to keep the total runtime sane. Currently, the whole `just test-e2e`
5353
target runs ~8'000 tests and takes around 5 minutes on my machine, exlucding
5454
binary and docker build time. I'd say that keeping it under 10 minutes is a good
5555
idea.

e2e_tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import os
22

3-
from helpers import *
4-
53

64
def pytest_configure(config):
75
os.environ["GIT_AUTHOR_NAME"] = "Example user"

e2e_tests/docker-rest/flask/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
app = Flask(__name__)
44
app.url_map.strict_slashes = False
55

6-
import github
7-
import gitlab
6+
import github # noqa: E402,F401
7+
import gitlab # noqa: E402,F401

e2e_tests/docker-rest/flask/github.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import os.path
22

3-
from app import app
4-
5-
from flask import Flask, request, abort, jsonify, make_response
6-
73
import jinja2
4+
from app import app
5+
from flask import abort, jsonify, make_response, request
86

97

108
def check_headers():
@@ -48,7 +46,7 @@ def args(page):
4846

4947
def read_project_files(namespaces=[]):
5048
last_page = 4
51-
page = username = int(request.args.get("page", "1"))
49+
page = int(request.args.get("page", "1"))
5250
response_file = f"./github_api_page_{page}.json.j2"
5351
if not os.path.exists(response_file):
5452
return jsonify([])

e2e_tests/docker-rest/flask/gitlab.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import os.path
22

3-
from app import app
4-
5-
from flask import Flask, request, abort, jsonify, make_response
6-
73
import jinja2
4+
from app import app
5+
from flask import abort, jsonify, make_response, request
86

97

108
def check_headers():
@@ -48,7 +46,7 @@ def args(page):
4846

4947
def read_project_files(namespaces=[]):
5048
last_page = 4
51-
page = username = int(request.args.get("page", "1"))
49+
page = int(request.args.get("page", "1"))
5250
response_file = f"./gitlab_api_page_{page}.json"
5351
if not os.path.exists(response_file):
5452
return jsonify([])

e2e_tests/helpers.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#!/usr/bin/env python3
22

3+
import hashlib
4+
import inspect
35
import os
46
import os.path
7+
import shutil
58
import subprocess
69
import tempfile
7-
import hashlib
8-
import shutil
9-
import inspect
1010

1111
import git
1212

@@ -176,7 +176,6 @@ def get(cls, cachekey=None, initfunc=None):
176176
newobj.remoteid = remoteid
177177
return newobj, remoteid
178178
else:
179-
refresh = False
180179
if cachekey not in cls.obj:
181180
tmpdir = get_temporary_directory()
182181
shell(

e2e_tests/test_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
from helpers import *
3+
from helpers import grm
44

55

66
def test_invalid_command():

e2e_tests/test_repos_find.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#!/usr/bin/env python3
22

3+
import os
4+
import re
35
import tempfile
46

5-
import toml
67
import pytest
8+
import toml
79
import yaml
8-
9-
from helpers import *
10+
from helpers import NonExistentPath, TempGitRepository, grm, shell
1011

1112

1213
def test_repos_find_nonexistent():
@@ -63,9 +64,10 @@ def test_repos_find_non_git_repos():
6364
assert len(cmd.stderr) != 0
6465

6566

66-
@pytest.mark.parametrize("default", [True, False])
67+
@pytest.mark.parametrize("default_format", [True, False])
6768
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
68-
def test_repos_find(configtype, default):
69+
@pytest.mark.parametrize("exclude", [None, "^.*/repo2$", "^not_matching$"])
70+
def test_repos_find(configtype, exclude, default_format):
6971
with tempfile.TemporaryDirectory() as tmpdir:
7072
shell(
7173
f"""
@@ -99,13 +101,19 @@ def test_repos_find(configtype, default):
99101
)
100102

101103
args = ["repos", "find", "local", tmpdir]
102-
if not default:
104+
if not default_format:
103105
args += ["--format", configtype]
106+
if exclude:
107+
args += ["--exclude", exclude]
104108
cmd = grm(args)
105109
assert cmd.returncode == 0
106-
assert len(cmd.stderr) == 0
110+
if exclude == "^.*/repo2$":
111+
assert re.match(r"^.*\[skipped\] .*\/repo2$", cmd.stderr.lower())
112+
assert "repo2" in cmd.stderr.lower()
113+
else:
114+
assert len(cmd.stderr) == 0
107115

108-
if default or configtype == "toml":
116+
if default_format or configtype == "toml":
109117
output = toml.loads(cmd.stdout)
110118
elif configtype == "yaml":
111119
output = yaml.safe_load(cmd.stdout)
@@ -120,7 +128,7 @@ def test_repos_find(configtype, default):
120128
assert set(tree.keys()) == {"root", "repos"}
121129
assert tree["root"] == tmpdir
122130
assert isinstance(tree["repos"], list)
123-
assert len(tree["repos"]) == 2
131+
assert len(tree["repos"]) == (1 if exclude == "^.*/repo2$" else 2)
124132

125133
repo1 = [r for r in tree["repos"] if r["name"] == "repo1"][0]
126134
assert repo1["worktree_setup"] is False
@@ -137,30 +145,33 @@ def test_repos_find(configtype, default):
137145
assert someremote["type"] == "ssh"
138146
assert someremote["url"] == "ssh://example.com/repo2.git"
139147

140-
repo2 = [r for r in tree["repos"] if r["name"] == "repo2"][0]
141-
assert repo2["worktree_setup"] is False
142-
assert isinstance(repo1["remotes"], list)
143-
assert len(repo2["remotes"]) == 1
148+
if exclude == "^.*/repo2$":
149+
assert [r for r in tree["repos"] if r["name"] == "repo2"] == []
150+
else:
151+
repo2 = [r for r in tree["repos"] if r["name"] == "repo2"][0]
152+
assert repo2["worktree_setup"] is False
153+
assert isinstance(repo1["remotes"], list)
154+
assert len(repo2["remotes"]) == 1
144155

145-
origin = [r for r in repo2["remotes"] if r["name"] == "origin"][0]
146-
assert set(origin.keys()) == {"name", "type", "url"}
147-
assert origin["type"] == "https"
148-
assert origin["url"] == "https://example.com/repo2.git"
156+
origin = [r for r in repo2["remotes"] if r["name"] == "origin"][0]
157+
assert set(origin.keys()) == {"name", "type", "url"}
158+
assert origin["type"] == "https"
159+
assert origin["url"] == "https://example.com/repo2.git"
149160

150161

151-
@pytest.mark.parametrize("default", [True, False])
162+
@pytest.mark.parametrize("default_format", [True, False])
152163
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
153-
def test_repos_find_in_root(configtype, default):
164+
def test_repos_find_in_root(configtype, default_format):
154165
with TempGitRepository() as repo_dir:
155166

156167
args = ["repos", "find", "local", repo_dir]
157-
if not default:
168+
if not default_format:
158169
args += ["--format", configtype]
159170
cmd = grm(args)
160171
assert cmd.returncode == 0
161172
assert len(cmd.stderr) == 0
162173

163-
if default or configtype == "toml":
174+
if default_format or configtype == "toml":
164175
output = toml.loads(cmd.stdout)
165176
elif configtype == "yaml":
166177
output = yaml.safe_load(cmd.stdout)
@@ -194,8 +205,8 @@ def test_repos_find_in_root(configtype, default):
194205

195206

196207
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
197-
@pytest.mark.parametrize("default", [True, False])
198-
def test_repos_find_with_invalid_repo(configtype, default):
208+
@pytest.mark.parametrize("default_format", [True, False])
209+
def test_repos_find_with_invalid_repo(configtype, default_format):
199210
with tempfile.TemporaryDirectory() as tmpdir:
200211
shell(
201212
f"""
@@ -229,13 +240,13 @@ def test_repos_find_with_invalid_repo(configtype, default):
229240
)
230241

231242
args = ["repos", "find", "local", tmpdir]
232-
if not default:
243+
if not default_format:
233244
args += ["--format", configtype]
234245
cmd = grm(args)
235246
assert cmd.returncode == 0
236247
assert "broken" in cmd.stderr
237248

238-
if default or configtype == "toml":
249+
if default_format or configtype == "toml":
239250
output = toml.loads(cmd.stdout)
240251
elif configtype == "yaml":
241252
output = yaml.safe_load(cmd.stdout)

0 commit comments

Comments
 (0)