aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/tests/test_publish_snapshot.py
blob: 3243d4b18fbc5bba6e546fa98104b2ccd75b781c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path

SCRIPT = Path(__file__).resolve().parent.parent / "scripts" / "publish_snapshot.py"
ENV = {**os.environ, "GIT_AUTHOR_NAME": "t", "GIT_AUTHOR_EMAIL": "t@t", "GIT_COMMITTER_NAME": "t",
       "GIT_COMMITTER_EMAIL": "t@t", "GIT_CONFIG_GLOBAL": "/dev/null"}


def git(cwd, *args):
    return subprocess.run(["git", *args], cwd=cwd, capture_output=True, text=True, env=ENV, check=True).stdout


class PublishSnapshotTest(unittest.TestCase):
    def setUp(self):
        self.tmp = tempfile.TemporaryDirectory()
        t = Path(self.tmp.name)
        self.src, self.dest, self.deny = t / "tool", t / "pub", t / "deny.txt"
        self.src.mkdir()
        git(self.src, "init", "-q", "-b", "master")
        self.put({"wf.py": "print('hi')\n", "CHANGES.md": "# Changes\n\n- 2026-01-01 first.\n",
                  "wflib/a.py": "x = 1\n", "docs/d.md": "doc\n",
                  "inbox.md": "tracked inbox\n", "out/log": "x\n", "sub/__pycache__/c.pyc": "bin\n"})
        (self.src / "wf.py").chmod(0o755)
        self.commit("one")
        self.deny.write_text("# private\nSecretProj\n\n")

    def tearDown(self):
        self.tmp.cleanup()

    def put(self, files):
        for p, text in files.items():
            f = self.src / p
            f.parent.mkdir(parents=True, exist_ok=True)
            f.write_text(text)

    def commit(self, msg):
        git(self.src, "add", "-A")
        git(self.src, "commit", "-qm", msg)

    def run_it(self, *extra):
        return subprocess.run([sys.executable, str(SCRIPT), str(self.dest), "--src", str(self.src),
                               "--denylist", str(self.deny), *extra], capture_output=True, text=True, env=ENV)

    def files(self):
        return sorted(git(self.dest, "ls-files").split())

    def test_first_run_one_commit_excludes(self):
        r = self.run_it()
        self.assertEqual(r.returncode, 0, r.stderr)
        self.assertEqual(self.files(), ["CHANGES.md", "docs/d.md", "wf.py", "wflib/a.py"])
        self.assertEqual(git(self.dest, "log", "--format=%s").splitlines(), ["initial public snapshot"])
        self.assertTrue(os.access(self.dest / "wf.py", os.X_OK))
        self.assertEqual(git(self.dest, "remote"), "")

    def test_denylist_hit_content_and_path_writes_nothing(self):
        self.put({"docs/d.md": "doc\nsee secretproj here\n", "SecretProj.md": "x\n"})
        self.commit("leak")
        r = self.run_it()
        self.assertEqual(r.returncode, 1)
        self.assertIn("docs/d.md:2: SecretProj", r.stderr)
        self.assertIn("SecretProj.md: SecretProj (path)", r.stderr)
        self.assertFalse(self.dest.exists())

    def test_uncommitted_files_not_published(self):
        (self.src / "wip.py").write_text("SecretProj\n")
        r = self.run_it()
        self.assertEqual(r.returncode, 0, r.stderr)
        self.assertNotIn("wip.py", self.files())

    def test_missing_or_empty_denylist_refuses(self):
        self.deny.unlink()
        r = self.run_it()
        self.assertEqual(r.returncode, 1)
        self.assertIn("no denylist", r.stderr)
        self.deny.write_text("# only comments\n")
        self.assertEqual(self.run_it().returncode, 1)
        self.assertFalse(self.dest.exists())

    def test_second_run_commit_message_new_changes_lines(self):
        self.run_it()
        self.put({"CHANGES.md": "# Changes\n\n- 2026-01-03 third.\n- 2026-01-02 second.\n- 2026-01-01 first.\n",
                  "wflib/b.py": "y = 2\n"})
        (self.src / "docs/d.md").unlink()
        self.commit("two")
        r = self.run_it()
        self.assertEqual(r.returncode, 0, r.stderr)
        self.assertEqual(git(self.dest, "log", "-1", "--format=%B").strip(),
                         "public snapshot\n\n- 2026-01-03 third.\n- 2026-01-02 second.")
        self.assertEqual(self.files(), ["CHANGES.md", "wf.py", "wflib/a.py", "wflib/b.py"])
        self.assertEqual(len(git(self.dest, "log", "--format=%h").split()), 2)

    def test_no_change_no_commit(self):
        self.run_it()
        r = self.run_it()
        self.assertEqual(r.returncode, 0, r.stderr)
        self.assertIn("nothing new", r.stdout)
        self.assertEqual(len(git(self.dest, "log", "--format=%h").split()), 1)

    def test_ref_option_and_never_touches_remote(self):
        self.run_it()
        git(self.dest, "remote", "add", "home", "/nonexistent")
        self.put({"wflib/a.py": "x = 2\n"})
        self.commit("two")
        self.assertEqual(self.run_it("--ref", "HEAD~1").stdout.strip(), "nothing new: no commit")
        r = self.run_it()
        self.assertIn("committed", r.stdout)
        self.assertEqual(git(self.dest, "remote").split(), ["home"])

    def test_nonempty_non_git_dest_refused(self):
        self.dest.mkdir()
        (self.dest / "keep.txt").write_text("x")
        r = self.run_it()
        self.assertEqual(r.returncode, 1)
        self.assertIn("not a git repo", r.stderr)


if __name__ == "__main__":
    unittest.main()