Skip to content

Commit 9555f41

Browse files
committed
add an initial version of GitHub Actions testing
This is also adapting the code in some aspects to make it compatible with older versions of Python and pygit2. Those adaptions are in particular: - Older versions of pygit2 didn't have enums FileMode and ObjectType. We define the needed values if they are missing. - Older versions of Python didn't provide default values for the to_bytes function. We provide the values ourselves now. - Older versions of pygit2 didn't convert object ids to strings implicitly. We do this explicitly now wherever needed. - Older versions of Python were less robust in parsing quotes nested in f-string literals. Work around those constructs that found to be problematic. The Windows build is currently disabled since there is still an issue with the remote helper that I need to debug. Ubuntuo 20.04 on ARM is also disbled because the machine currently does not seem to start up on GitHub.
1 parent 4b0afa0 commit 9555f41

File tree

4 files changed

+129
-18
lines changed

4 files changed

+129
-18
lines changed

.github/workflows/test.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Test
2+
on: [push]
3+
jobs:
4+
test:
5+
runs-on: ${{ matrix.os }}
6+
strategy:
7+
matrix:
8+
os:
9+
- ubuntu-20.04
10+
#- ubuntu-20.04-arm
11+
- ubuntu-22.04
12+
- ubuntu-22.04-arm
13+
- ubuntu-24.04
14+
- ubuntu-24.04-arm
15+
- macos-13
16+
- macos-14
17+
- macos-15
18+
#- windows-2019
19+
steps:
20+
- name: Install system dependencies (Ubuntu)
21+
if: startsWith(matrix.os, 'ubuntu')
22+
run: |
23+
sudo apt-get update
24+
sudo apt-get install -y asciidoc python3-pygit2 python3-pip
25+
- name: Install system dependencies (MacOS)
26+
if: startsWith(matrix.os, 'macos')
27+
run : |
28+
brew update
29+
brew install asciidoc xmlto libgit2
30+
HOMEBREW_PREFIX=$(brew --prefix)
31+
echo "XML_CATALOG_FILES=${HOMEBREW_PREFIX}/etc/xml/catalog" >> $GITHUB_ENV
32+
- name: Install Python packages (Posix)
33+
if: runner.os != 'Windows'
34+
run: |
35+
python3 -m venv ~/venv
36+
source ~/venv/bin/activate
37+
python3 -m pip install --upgrade pip
38+
python3 -m pip install pylint pycodestyle pygit2 cryptography asciidoc
39+
- name: Install Python packages (Windows)
40+
if: runner.os == 'Windows'
41+
run: |
42+
python3 -m venv $env:USERPROFILE\venv
43+
"$env:USERPROFILE\venv\Scripts\activate"
44+
python3 -m pip install --upgrade pip
45+
python3 -m pip install pylint pycodestyle pygit2 cryptography asciidoc
46+
- name: Checkout
47+
uses: actions/checkout@v4
48+
with:
49+
fetch-depth: 0
50+
- name: Test (Posix)
51+
if: runner.os != 'Windows'
52+
run: |
53+
git config --global user.email "[email protected]"
54+
git config --global user.name "Test User"
55+
gpg --batch --gen-key .github/workflows/testkey.conf
56+
source ~/venv/bin/activate
57+
make KEY:=$(gpg --list-keys --with-colons | awk -F: '/^pub/ {print $5; exit}') test
58+
- name: Test (Windows)
59+
if: runner.os == 'Windows'
60+
run: |
61+
git config --global user.email "[email protected]"
62+
git config --global user.name "Test User"
63+
gpg --batch --gen-key .github/workflows/testkey.conf
64+
dir
65+
"$env:USERPROFILE/venv/Scripts/activate"
66+
rm git-remote-incrypt
67+
cp git-incrypt git-remote-incrypt
68+
dir
69+
make KEY:=$(gpg --list-keys --with-colons | awk -F: '/^pub/ {print $5; exit}') NODOC:=1 VERBOSE:=-vvv test

.github/workflows/testkey.conf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
%no-protection
2+
Key-Type: RSA
3+
Key-Length: 2048
4+
Subkey-Type: RSA
5+
Subkey-Length: 2048
6+
Name-Real: Test User
7+
Name-Email: [email protected]
8+
Expire-Date: 0
9+
%commit

Makefile

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
export PATH := $(CURDIR):$(PATH)
2-
export MANPATH := $(CURDIR):$(MANPATH)
1+
ifeq ($(OS),Windows_NT)
2+
PATHSEP = ;
3+
else
4+
PATHSEP = :
5+
endif
6+
export GIT_EXEC_PATH := $(CURDIR)$(PATHSEP)$(shell git --exec-path)
7+
export MANPATH := $(CURDIR)$(PATHSEP)$(MANPATH)
38
VERBOSE :=
49
TESTREPO := $(CURDIR)
510
KEY := 5A8A11E44AD2A1623B84E5AFC5C0C5C7218D18D7
@@ -8,7 +13,15 @@ REPO := incrypt::$(CURDIR)/crypt
813
.PHONY: all man test clean
914

1015
all: man
16+
17+
ifndef NODOC
1118
man: man1/git-incrypt.1
19+
testman: man
20+
PAGER= git incrypt --help
21+
else
22+
man:
23+
testman:
24+
endif
1225

1326
man1/%.1: man1/%.xml manpage-normal.xsl manpage-bold-literal.xsl
1427
cd man1 && xmlto $(patsubst %,-m ../%,$(wordlist 2, 3, $^)) man ../$<
@@ -17,22 +30,21 @@ man1/%.xml: %.adoc asciidoc.conf
1730
mkdir -p man1
1831
asciidoc -f $(word 2, $^) -b docbook -d manpage -o $@ $<
1932

20-
test: man
21-
PAGER= git incrypt --help
33+
test: testman
2234
rm -rf crypt tst
2335
mkdir crypt
2436
git -C crypt init --bare -b _
2537
git ls-remote $(TESTREPO)
2638
git incrypt init $(REPO) $(KEY)
2739
git -C $(TESTREPO) fetch $(REPO) || git -C $(TESTREPO) incrypt trust $(REPO)
28-
git -C $(TESTREPO) push $(VERBOSE) $(REPO) master~2:refs/heads/master
40+
git -C $(TESTREPO) push $(VERBOSE) $(REPO) HEAD~2:refs/heads/master
2941
git clone $(VERBOSE) $(REPO) tst
3042
git -C $(TESTREPO) push $(VERBOSE) $(REPO) v0.9.0
3143
git -C tst pull $(VERBOSE)
32-
git -C $(TESTREPO) push $(VERBOSE) $(REPO) master
33-
git -C tst pull $(VERBOSE)
34-
git -C $(TESTREPO) push $(VERBOSE) --all $(REPO)
44+
git -C $(TESTREPO) push $(VERBOSE) $(REPO) HEAD:master
3545
git -C tst pull $(VERBOSE)
46+
git -C $(TESTREPO) push $(VERBOSE) -f --all $(REPO)
47+
git -C tst pull --no-rebase -X theirs --no-edit $(VERBOSE)
3648
git ls-remote crypt
3749
git -C tst ls-remote $(REPO)
3850
git ls-remote tst

git-incrypt

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
3535
from cryptography.hazmat.primitives import padding
3636
from cryptography.hazmat.backends import default_backend
3737

38+
if not hasattr(pygit2.enums, 'FileMode'):
39+
class FileMode(enum.IntFlag):
40+
'definitions missing in older versions of pygit2'
41+
# pylint: disable=c-extension-no-member disable=protected-access
42+
TREE = pygit2._pygit2.GIT_FILEMODE_TREE
43+
# pylint: disable=c-extension-no-member disable=protected-access
44+
BLOB = pygit2._pygit2.GIT_FILEMODE_BLOB
45+
pygit2.enums.FileMode = FileMode
46+
if not hasattr(pygit2.enums, 'ObjectType'):
47+
class ObjectType(enum.IntEnum):
48+
'definitions missing in older versions of pygit2'
49+
# pylint: disable=c-extension-no-member disable=protected-access
50+
COMMIT = pygit2._pygit2.GIT_OBJ_COMMIT
51+
# pylint: disable=c-extension-no-member disable=protected-access
52+
TREE = pygit2._pygit2.GIT_OBJ_TREE
53+
# pylint: disable=c-extension-no-member disable=protected-access
54+
BLOB = pygit2._pygit2.GIT_OBJ_BLOB
55+
# pylint: disable=c-extension-no-member disable=protected-access
56+
TAG = pygit2._pygit2.GIT_OBJ_TAG
57+
pygit2.enums.ObjectType = ObjectType
58+
3859
CRYPTREADME = '''# 401 Unauthorized
3960
4061
This is an encrypted git repository. You can clone it, but you will not be
@@ -275,8 +296,8 @@ class CryptRepo:
275296
'encrypt an object'
276297
clear = self.clearrepo.get(oid)
277298
cryptobjs[clear.id] = self.repo.create_blob(encryptdata(
278-
clear.id.raw + clear.type.to_bytes(1) + clear.read_raw(),
279-
self.meta.key))
299+
clear.id.raw + clear.type.to_bytes(1, byteorder='big') +
300+
clear.read_raw(), self.meta.key))
280301

281302
def createcommit(oid):
282303
'create a commit'
@@ -304,12 +325,12 @@ class CryptRepo:
304325
pygit2.enums.FileMode.BLOB)
305326
colid = collector.write()
306327
cryptmap[str(obj.id)] = self.meta.secretcommit(
307-
colid, [cryptmap[c] for c in obj.parent_ids]
328+
colid, [cryptmap[str(c)] for c in obj.parent_ids]
308329
if obj.type == pygit2.enums.ObjectType.COMMIT
309-
else [cryptmap[obj.target]])
330+
else [cryptmap[str(obj.target)]])
310331

311332
xrefs = [[r[0], r[1], r[3],
312-
f'{'+' if r[2] else ''}{r[3] if r[0] else ''}:{r[3]}',
333+
f"{'+' if r[2] else ''}{r[3] if r[0] else ''}:{r[3]}",
313334
self.clearrepo.revparse_single(r[0]) if r[0] else None]
314335
for r in [[r[0], r[1], r[2], encryptrefname(r[1],
315336
self.meta.key)] for r in refs]]
@@ -325,7 +346,7 @@ class CryptRepo:
325346
self.meta.write(cryptmap)
326347
for r in xrefs:
327348
if r[4]:
328-
self.repo.create_reference(r[2], cryptmap[r[4].id],
349+
self.repo.create_reference(r[2], cryptmap[str(r[4].id)],
329350
force=True)
330351
else:
331352
try:
@@ -379,9 +400,9 @@ def remotehelperloop():
379400
refs.append([src, dst, force])
380401
line = sys.stdin.readline().strip()
381402
results = crypt.push(refs)
382-
sys.stdout.write(f'{
403+
sys.stdout.write('{}\n'.format(
383404
''.join([(f'error {r} {e}\n' if e else f'ok {r}\n')
384-
for r, e in results.items()])}\n')
405+
for r, e in results.items()])))
385406

386407
crypt = CryptRepo(os.environ.pop('GIT_DIR', None), sys.argv[2])
387408
while True:
@@ -393,8 +414,8 @@ def remotehelperloop():
393414
if command[0] == 'capabilities':
394415
sys.stdout.write('fetch\npush\noption\n\n')
395416
elif command[0] == 'list':
396-
sys.stdout.write(f'{''.join([f'{r[1]} {r[0]}\n'
397-
for r in crypt.getrefs()])}\n')
417+
sys.stdout.write('{}\n'.format(
418+
''.join([f'{r[1]} {r[0]}\n' for r in crypt.getrefs()])))
398419
elif command[0] == 'fetch':
399420
fetchcommand(line)
400421
elif command[0] == 'push':

0 commit comments

Comments
 (0)