-
Notifications
You must be signed in to change notification settings - Fork 7
/
DEVELOPERS
260 lines (171 loc) · 9.81 KB
/
DEVELOPERS
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
Context and Background
======================
In Tahoe-LAFS 1.14.0 and earlier, "magic folders" was a subcommand.
This project moves it out of tahoe, interacting with Tahoe only via its HTTP API.
There are still some remnants of this history; some `allmydata` imports for example.
This means a Python dependency on Tahoe (even though Tahoe-LAFS has no official Python API).
We are working to get rid of this so that all we need is a Tahoe-LAFS WebUI endpoint to connect to.
Where possible, new code should not use `allmydata.*` namespaces.
This is not always possible.
One place it's okay is for handling of Capability Strings directly (roughly, parts of `allmydata.uri.*`)
Magic Folder is currently Python2 only.
A port of Tahoe-LAFS to Python3 is under way currently.
It doesn't make sense to support Python3 in Magic Folders until Tahoe-LAFS (at least) supports it.
General Development Process
===========================
Development is co-ordinated on GitHub via Issues and Pull Requests.
Generally any change requires a new Issue describing the feature, bug or enhancement.
This Issue number will be used for a "news" item in ``./newsfragments/<number>.<kind>``, referenced by the eventual Pull Request(s) and are normally used in the branch name (such as ``<number>.descriptive-words``).
The different values for ``<kind>`` can be found in ``pyproject.toml``.
Magic Folder is on-topic for the ``#tahoe-lafs`` channel on the Libera IRC network.
Feel free to discuss things there but be prepared to wait hours or more for replies; there aren't many people working on Magic Folder and we are in many time-zones.
Setting up a Development Environment
====================================
There are many ways to set up development environments for Python programs.
While we describe particular ways below you may wish to try different methods.
If you believe a different setup could serve other developers add those instructions here too (via a Pull Request).
Creating a virtualenv
---------------------
If you like to work using a virtualenv you will need a Python one for magic-folder.
One way to create it is::
% python3 -m virtualenv venv
% ./venv/bin/pip install --editable .[test]
Note the ``[test]`` "extra" after the "." (single dot).
This installs tools required for local development.
Hypothesis
----------
Many of the tests use Hypothesis (see https://hypothesis.readthedocs.io/).
You can select profiles with an environment variable:
export MAGIC_FOLDER_HYPOTHESIS_PROFILE=magic-folder-fast
export MAGIC_FOLDER_HYPOTHESIS_PROFILE=magic-folder-ci
Tests can make use of Hypothesis to create a variety of inputs.
The range of inputs tried is kept in a database in ``./hypothesis``.
The ``magic-folder-fast`` profile above limits the number of "examples" that Hypothesis tries per test-case; this speeds up the tests but it can be useful to run with more examples occasionally.
Test Tools
----------
Newer tests are using the "testttools" framework (see https://testtools.readthedocs.io/en/latest/overview.html).
These asserts use the method ``self.assertThat(...)`` along with some "matchers".
When writing new code, this style should be preferred.
If you have motivation, re-writing older tests in this style is also useful.
Tox
---
There exist several Tox environments (list them with ``tox -a``).
Before pushing a branch it is a good idea to run at least the "codechecks" environment::
% tox -e codechecks
This is the "lint" job on the Continuous Integration (CI) system and will fail your Pull Request if it fails.
You may also choose to run the various tests via tox.
Using tox to run these tests will be closer to the way the CI system will run them.
Mock
----
No tests shall use the `mock.Mock` or `mock.MagicMock` classes. For more information, see:
* https://nedbatchelder.com/blog/201206/tldw_stop_mocking_start_testing.html to start
* https://pythonspeed.com/articles/verified-fakes/
* https://martinfowler.com/articles/mocksArentStubs.html
Exceptions and @attr.s
----------------------
In Python3, Twisted removes the __traceback__ attribute from exceptions in some cases.
Thus, no `Exception`-derived, `@attr.s()`-using class may use `frozen=True`.
FilePath and text versus binary mode
------------------------------------
`twisted.python.filepath.FilePath` operates in "bytes" mode or "text" mode with conversion functions `.asTextMode()` and `.asBytesMode()`.
Internally, all `FilePath`s shall be text mode.
Outside users might need to call `.asTextMode()` on a FilePath to ensure this.
Submitting a Pull Request
=========================
Let us say that you've gotten the project from our main GitHub repository::
% git clone https://github.com/LeastAuthority/magic-folder
Creating Your Fork
~~~~~~~~~~~~~~~~~~
To make a Pull Request (PR) you will need to make a "fork" of the project under your own username.
Click the "fork" button near the upper-right corner.
Once this is complete you can add your fork as an additional repository.
You may name it however you like; this example calls it "github" (the first place you cloned from will be called "origin" by default).
Add your fork; from the "Code" dropdown select the "SSH" tab::
% git remote add -f github [email protected]:meejah/magic-folder.git
The "-f" option causes it to "fetch" immediately.
Creating a Development Branch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Make sure you're on "main" and up-to-date:
% git checkout main
% git pull
If there is not already an Issue for your change, create one.
This Issue should describe the bug or feature or enhancement from a high level.
Let us say it has number "123".
Create an appropriate branch::
% git checkout -b 123.embiggen-the-memory
This creates the branch "123.embiggen-the-memory" and switches to it.
Prepare to Push Your Work
~~~~~~~~~~~~~~~~~~~~~~~~~
After you make some changes and commits, run the "codechecks" environment:
% tox -e codechecks
In this case, it will likely complain about a missing "newsfragment".
These fragments are used by ``towncrier`` to construct a NEWS file for each release.
Create a newsfragment for your change:
% echo "Now uses even more memory" > newsfragments/123.feature
...and add it to your branch::
% git add newsfragments/123.feature
% git commit -m "news"
Creating the Pull Request
~~~~~~~~~~~~~~~~~~~~~~~~~
You may now "push" your branch to your own fork::
% git push github
The "github" above needs to be the same name as you used when adding the remote.
GitHub usually offers you a link to create a new PR.
Follow the link or visit the GitHub UI which will often also offer you a way to create the PR.
If you expect to do further work, create the PR as a "draft" PR.
Getting a Review
~~~~~~~~~~~~~~~~
All pull-requests must be reviewed by a current core developer.
Once your Pull Request has been created, Continuous Integration will be run.
If any CI steps fail you will need to complete more work until they do not fail.
Once you are happy with the changes and the CI run is "green" / okay the PR is ready to be reviewed.
Add the "needs-review" label.
Ideally a developer will notice and review your work quickly. If not, mentioning it in IRC may help draw attention.
One of two things will happen: your PR will be approved and merged or the reviewer will ask for changes.
In the latter case, you make these changes, push them to your branch and get the attention of a reviewer again.
Philosophy of New Code Changes
==============================
As some of this code is fairly old there may be several "styles" of doing things present already.
Where consensus has been reached by core developers, we note "the new way" of writing code here.
If in doubt, reach out on IRC or via a "question" Issue on GitHub.
- Use "testtools" style unit-tests (see above too)
- Use Hypothesis when inputs may be varied
- The vast majority of user-facing commands should be HTTP APIs
- ``magic-folder *`` CLI commands should use the HTTP API
- A single user-facing command may need to make several HTTP transactions
- There may be exceptions: ``magic-folder run``, ``magic-folder init`` etc. obviously cannot contact a running Magic Folder daemon
- Configuration goes in a database (there is "global" configuration and "per-magic-folder" configuration which have separate databases)
- All Tahoe interactions should be via Tahoe-LAFS "WebUI" (HTTP) transactions
- most such Tahoe endpoints have a ``?t=json`` option to return JSON instead of HTML
- if Tahoe lacks a ``?t=json`` option for a page that should be fixed first (in Tahoe)
- no scraping HTML!
- New code should be covered by unit-tests
Creating a Release
==================
- Use a fresh virtualenv with the version of Python you want. For example:
- pyenv shell 3.9.2
- python -m venv buildvenv
- source ./buildvenv/bin/activate
- Install the tools required:
- python3 -m pip install --editable .[build]
- Update the NEWS:
- VERSION=$(python3 misc/build_helpers/update-version.py --no-tag) python3 -m towncrier build --yes --version ${VERSION}
- git diff --cached
- git commit -m "update NEWS"
- Update the version:
- (if there is a better way to tell GnuPG to cache the key, please reach out)
- convince GnuPG to unlock a key: gpg --pinentry=loopback --decrypt ~/something.asc
- python3 misc/build_helpers/update-version.py
- Build the release:
- python3 setup.py bdist_wheel
- Double-check the artifact in dist/
- Sign the wheel if you're happy:
- export VERSION=23.3.0
- gpg --pinentry=loopback --armor --detach-sign dist/magic_folder-${VERSION}-py3-none-any.whl
- Make source-dist and sign:
- python setup.py sdist
- gpg --pinentry=loopback --armor --detach-sign dist/magic-folder-${VERSION}.tar.gz
- OR: do all the above steps with "make release"
- Publish the release:
- twine upload dist/magic_folder-*-py3-none-any.whl dist/magic_folder-*-py3-none-any.whl.asc
- OR: do all the publish steps with "make release-upload"