Skip to content

Commit cf60324

Browse files
committed
Fix CI
1 parent 7a468b1 commit cf60324

File tree

8 files changed

+388
-64
lines changed

8 files changed

+388
-64
lines changed

.github/workflows/nox.yaml

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,77 @@ on:
88
workflow_dispatch:
99

1010

11+
# Limit this workflow to a single run at a time per-branch to avoid wasting worker resources
1112
concurrency:
1213
group: ${{ github.workflow }}-${{ github.ref }}
1314
cancel-in-progress: true
1415

1516

17+
env:
18+
# hardlinks don't work in containers and just spam the logs with warning messages
19+
# UV_LINK_MODE: copy
20+
UV_DISABLE_UPDATE: '1'
21+
22+
23+
1624
jobs:
17-
nox:
25+
# JOB: NOX-OTHER
26+
# nox-other:
27+
# runs-on: ubuntu-latest
28+
29+
# strategy:
30+
# fail-fast: false
31+
# matrix:
32+
# session: [precommit, audit]
33+
34+
# steps:
35+
# - uses: level12/coppy/gh-actions/nox-run@main
36+
# with:
37+
# nox-session: ${{ matrix.session }}
38+
39+
# JOB: NOX-PYTEST
40+
nox-pytest:
1841
runs-on: ubuntu-latest
1942

2043
steps:
2144
- name: Checkout Code
2245
uses: actions/checkout@v4
46+
with:
47+
# Copier errors out with a shallow git checkout, which is the action's default.
48+
fetch-depth: 0
49+
50+
- name: Mark repo as safe for Git
51+
shell: bash
52+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
53+
54+
# NOTE: use GH's action to install Python b/c uv docs say it will be faster due to caching
55+
- name: "Set up Python"
56+
uses: actions/setup-python@v5
57+
with:
58+
python-version-file: pyproject.toml
59+
60+
- name: Install uv
61+
uses: astral-sh/setup-uv@v6
62+
63+
# - uses: level12/coppy/gh-actions/uv-prep@main
64+
65+
- name: Add runner user to test user group
66+
run: |
67+
# The script returns early after adding this user to the new user's group.
68+
# This is due to the need to "logout" before the user pick's up the group's identity.
69+
70+
# Also, the creation of the user with Ubuntu's `useradd` command hangs for 20-30s but
71+
# only in CI. Go figure.
72+
uv run --no-dev tasks/test-user-prep.py
73+
74+
- name: Finish prepping test user
75+
run: |
76+
uv run --no-dev tasks/test-user-prep.py --systemd-skip
2377
24-
- name: Add ~/bin to PATH
25-
run: echo "PATH=/home/runner/bin:$PATH" >> $GITHUB_ENV
78+
sudo setfacl --recursive -m g:coppy-tests:rwX /home/coppy-tests/
79+
sudo setfacl --recursive -d -m g:coppy-tests:rwX /home/coppy-tests/
80+
sudo -u coppy-tests mkdir /home/coppy-tests/.cache/uv
2681
27-
- name: Prep
82+
- name: Run pytest
2883
run: |
29-
# Mise
30-
mkdir ~/bin
31-
curl -LsS https://mise.jdx.dev/mise-latest-linux-x64 > ~/bin/mise
32-
chmod +x ~/bin/mise
33-
34-
# build the image used to test
35-
mise docker-build
36-
37-
# uv
38-
mise use -g ubi:astral-sh/uv
39-
mkdir -p /home/runner/.local/share/uv/python/
40-
41-
# Prep mise
42-
mise trust
43-
mise install
44-
45-
# Uncomment to help troubleshooting
46-
# - name: Debug info
47-
# run: |
48-
# # Python versions
49-
# echo "Python versions:"
50-
# mise exec -- python --version
51-
# mise exec -- uv run python --version
52-
53-
# # Path
54-
# echo "Path:"
55-
# echo $PATH
56-
57-
# mise demo --no-bootstrap --no-nox
58-
# mise sandbox --doctor
59-
60-
- name: nox
61-
run: mise exec -- uv run --frozen --only-group nox nox
84+
uv run --frozen --only-group nox -- nox -s pytest -- -x

.github/workflows/useradd.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Useradd
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
11+
# Limit this workflow to a single run at a time per-branch to avoid wasting worker resources
12+
concurrency:
13+
group: ${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
build:
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Add Ubuntu User
22+
run: |
23+
sudo useradd --system --create-home --shell=/bin/bash coppy-tests

noxfile.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,59 @@
77
nox.options.default_venv_backend = 'uv'
88

99

10-
def uv_sync(session, group: str, project: bool = False):
11-
# NOTE: not sure why, but sys.path doesn't get correctly configured to include the coppy pkg's
12-
# `src` directory when using '--only-group'. But, in a templated generated app, like the
13-
# coppy demo, '--only-group' works just fine. I spent some time trying to debug but am punting
14-
# for now since the problem/solution seem convoluted to me.
15-
groups_args = ('--no-default-groups', '--group') if project else ('--only-group',)
16-
session.run('uv', 'sync', '--active', '--frozen', *groups_args, group)
17-
18-
1910
@nox.session
20-
def tests(session: nox.Session):
21-
uv_sync(session, 'tests', project=True)
11+
def pytest(session: nox.Session):
12+
uv_sync(session)
13+
# TODO: no coverage because the far majority of the code in this project is just for testing.
14+
# But it wouldn't hurt to add it.
2215
session.run(
2316
'pytest',
2417
'-ra',
2518
'--tb=native',
2619
'--strict-markers',
27-
f'--junit-xml={package_path}/ci/test-reports/{session.name}.pytests.xml',
2820
'tests',
2921
*session.posargs,
3022
)
3123

3224

3325
@nox.session
34-
def standards(session: nox.Session):
26+
def precommit(session: nox.Session):
3527
uv_sync(session, 'pre-commit')
3628
session.run(
3729
'pre-commit',
3830
'run',
3931
'--all-files',
4032
)
33+
34+
35+
@nox.session
36+
def audit(session: nox.Session):
37+
# Much faster to install the deps first and have pip-audit run against the venv
38+
uv_sync(session)
39+
session.run(
40+
'pip-audit',
41+
'--desc',
42+
'--skip-editable',
43+
)
44+
45+
46+
def uv_sync(session: nox.Session, *groups, project=False, extra=None):
47+
# If no group given, assume group shares name of session.
48+
if not groups:
49+
groups = (session.name,)
50+
51+
# At least pytest needs the project installed.
52+
project_args = () if project or session.name.startswith('pytest') else ('--no-install-project',)
53+
54+
group_args = [arg for group in groups for arg in ('--group', group)]
55+
extra_args = ('--extra', extra) if extra else ()
56+
run_args = (
57+
'uv',
58+
'sync',
59+
'--active',
60+
'--no-default-groups',
61+
*project_args,
62+
*group_args,
63+
*extra_args,
64+
)
65+
session.run(*run_args)

pyproject.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ coppy = 'coppy.cli:cli'
2626

2727
[dependency-groups]
2828
dev = [
29-
{include-group = "tests"},
29+
{include-group = "pytest"},
3030
{include-group = "pre-commit"},
3131
{include-group = "nox"},
32-
"hatch>=1.14.0",
3332
"ruff>=0.9.6",
3433
"towncrier>=25.8.0",
3534
]
@@ -39,8 +38,13 @@ pre-commit = [
3938
'pre-commit-uv>=4.1.4',
4039
]
4140
# Used by nox
42-
tests = [
41+
pytest = [
4342
'pytest>=8.3.4',
43+
"hatch>=1.14.0",
44+
]
45+
# Used by nox
46+
audit = [
47+
'pip-audit',
4448
]
4549
# Used by CI
4650
nox = [

tasks/test-user-prep.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,43 +24,51 @@
2424
@click.option('--reinstall', is_flag=True, default=False)
2525
@logs.opts_init
2626
def main(systemd_skip: bool, systemd_force: bool, reinstall: bool):
27+
log.info('Test user prep starting...')
28+
2729
coppy_user = User(username)
2830

2931
if reinstall and coppy_user.exists():
3032
result = utils.sudo_run('pkill', '-u', username, returns=(0, 1))
3133
if result.returncode == 0:
34+
log.info('Waiting on all coppy-tests processes to exit')
3235
# Wait for user's processes to exit or userdel will fail
3336
utils.sub_run('pidwait', '-u', username)
3437
utils.sudo_run('userdel', '-r', username)
3538

3639
# Get rid of cache
3740
coppy_user = User(username)
3841

42+
log.info('Ensuring user exists...')
3943
coppy_user.ensure()
4044
coppy_user_home = coppy_user.home_dir()
4145

4246
if not coppy_user.is_current:
47+
log.info('Adjustments to give current user access to coppy-tests home')
4348
curr_user = User.current()
44-
# This would clear them all (i.e. fix a mistake if you have one)
45-
utils.sub_run('sudo', 'setfacl', '-R', '-b', coppy_user_home)
46-
# utils.sudo_run('setfacl', '-R', '-m', f'u:{curr_user.name}:rwX', coppy_user_home)
47-
# utils.sudo_run('setfacl', '-R', '-d', '-m', f'u:{curr_user.name}:rwX', coppy_user_home)
49+
4850
if coppy_user.name not in curr_user.groups():
4951
log.info(f'Adding your user to the user group: {coppy_user.name}')
5052
utils.sudo_run('usermod', '-aG', coppy_user.name, curr_user.name)
5153
log.warning(
5254
f'Please logout and then back in to enable access to the {coppy_user.name} group.',
5355
)
56+
return
5457
else:
5558
log.info(f'Your user is already in the group: {coppy_user.name}')
5659

5760
# Sticky group so files created by the dev's user can be accessed by coppy-tests user.
5861
utils.sudo_run('chmod', 'g+ws', coppy_user_home)
5962

60-
# Needed for systemd files
6163
config_dpath = coppy_user_home / '.config/'
6264
config_dpath.mkdir(exist_ok=True)
65+
utils.sudo_run('chmod', '-R', 'g+ws', config_dpath)
66+
67+
cache_dpath = coppy_user_home / '.cache/'
68+
cache_dpath.mkdir(exist_ok=True)
69+
utils.sudo_run('chmod', '-R', 'g+ws', cache_dpath)
6370

71+
log.info('Updating sudoers for passwordless access to coppy test user')
6472
sudoers_write('coppy', sudoers.format(coppy_user=username))
6573

6674
# Mise & uv

template/tasks/mise-uv-init.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,13 @@ def slugify(text):
7373

7474

7575
def print_log(*args, **kwargs):
76-
# TODO: would it be more helpful to print errors on stderr like mise/uv do?
7776
with paths.log().open('a') as fo:
78-
print(*args, file=fo)
77+
print(*args, file=fo, **kwargs)
78+
79+
80+
def print_err(*args, **kwargs):
81+
print(*args, file=sys.stderr, **kwargs)
82+
print_log(*args, **kwargs)
7983

8084

8185
def sub_run(*args, env=None) -> str:
@@ -85,10 +89,10 @@ def sub_run(*args, env=None) -> str:
8589
try:
8690
result = subprocess.run(args, check=True, text=True, capture_output=True, env=env)
8791
if result.stderr:
88-
print_log(args, '\n', result.stderr)
92+
print_err(args, '\n', result.stderr)
8993
except subprocess.CalledProcessError as e:
9094
if e.stderr:
91-
print_log(args, '\n', e.stderr)
95+
print_err(args, '\n', e.stderr)
9296
raise
9397

9498
return result.stdout.strip()

tests/coppy_tests/libs/os_prep.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def ensure(self):
9595
if self.name in Group.all_names():
9696
group_args = ('-g', self.name)
9797

98+
log.info(f'Creating user: {self.name}')
9899
utils.sudo_run(
99100
'useradd',
100101
'--system',
@@ -221,6 +222,7 @@ def install(self):
221222
self.sh_install(
222223
'https://astral.sh/uv/install.sh',
223224
self.uv_bin,
225+
UV_DISABLE_UPDATE='1',
224226
)
225227

226228
def systemd(self, force: bool = False):

0 commit comments

Comments
 (0)