noren 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- noren-0.1.0/.gitignore +6 -0
- noren-0.1.0/LICENSE +21 -0
- noren-0.1.0/PKG-INFO +205 -0
- noren-0.1.0/README.ja.md +193 -0
- noren-0.1.0/README.md +193 -0
- noren-0.1.0/pyproject.toml +48 -0
- noren-0.1.0/src/noren/__init__.py +5 -0
- noren-0.1.0/src/noren/_version.py +24 -0
- noren-0.1.0/src/noren/cli.py +119 -0
- noren-0.1.0/src/noren/git.py +63 -0
- noren-0.1.0/src/noren/publishing.py +259 -0
- noren-0.1.0/src/noren/setup.py +42 -0
- noren-0.1.0/tests/conftest.py +136 -0
- noren-0.1.0/tests/test_checks.py +232 -0
- noren-0.1.0/tests/test_gitignore.py +59 -0
- noren-0.1.0/tests/test_init.py +75 -0
- noren-0.1.0/tests/test_publish.py +261 -0
- noren-0.1.0/tests/test_regressions.py +94 -0
- noren-0.1.0/uv.lock +128 -0
noren-0.1.0/.gitignore
ADDED
noren-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 minamik
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
noren-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: noren
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Send selected files from one git repository to another as a single commit
|
|
5
|
+
Project-URL: Repository, https://github.com/sync-dev-org/noren
|
|
6
|
+
Author-email: minamik <10973755+minamikik@users.noreply.github.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.12
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# noren
|
|
14
|
+
|
|
15
|
+
[日本語](README.ja.md)
|
|
16
|
+
|
|
17
|
+
noren sends selected files from one Git repository to another as a single commit; it does not publish packages to a registry.
|
|
18
|
+
|
|
19
|
+
Use it, for example, to send a public snapshot of a private repository to GitHub. The destination receives the selected files, the commit message you supply, and the configured author and committer. Source commits, their messages, and annotated-tag messages are not copied. File paths and file contents that you select are copied.
|
|
20
|
+
|
|
21
|
+
## Install and choose how to run
|
|
22
|
+
|
|
23
|
+
You need Python 3.12 or later, Git, and [uv](https://docs.astral.sh/uv/). Run commands inside the source Git repository.
|
|
24
|
+
|
|
25
|
+
Add noren as a development dependency of your Python project:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
uv add --dev noren
|
|
29
|
+
uv run noren --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Alternatively, [uvx](https://docs.astral.sh/uv/guides/tools/) runs noren in an isolated environment without adding it to your project's dependencies:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
uvx noren --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The examples below use `uv run noren`. If you chose uvx, replace that prefix with `uvx noren`. If noren is already available in your environment, you can use `noren` directly. `noren init` and `noren publish` work without interactive input.
|
|
39
|
+
|
|
40
|
+
## Initial setup
|
|
41
|
+
|
|
42
|
+
The source repository must have an `origin` remote. Create a separate destination repository on GitHub and make sure your usual Git authentication can read it and push to it. noren uses `https://github.com/OWNER/REPO.git`, with your existing Git configuration.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
uv run noren init
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`noren init` takes no arguments and creates `noren.yaml` and `noren-words.txt` at the source repository root, even when run from a subdirectory. It prints setup instructions, exits with 0 on success, and reports errors to stderr with a nonzero exit code. It refuses to overwrite either file and creates neither file if `origin` is missing.
|
|
49
|
+
|
|
50
|
+
### Configure noren.yaml
|
|
51
|
+
|
|
52
|
+
Edit the generated template. This example sends `README.md`, `LICENSE`, and files under `src/`, except `src/internal/`. Replace `OWNER/public-project` with your destination:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
destination: OWNER/public-project
|
|
56
|
+
include: |
|
|
57
|
+
README.md
|
|
58
|
+
LICENSE
|
|
59
|
+
src/
|
|
60
|
+
exclude: |
|
|
61
|
+
src/internal/
|
|
62
|
+
private/
|
|
63
|
+
tests/
|
|
64
|
+
.github/
|
|
65
|
+
.nf/
|
|
66
|
+
.gitignore
|
|
67
|
+
pyproject.toml
|
|
68
|
+
uv.lock
|
|
69
|
+
noren.yaml
|
|
70
|
+
noren-words.txt
|
|
71
|
+
word-list: noren-words.txt
|
|
72
|
+
author:
|
|
73
|
+
name: Release Bot
|
|
74
|
+
email: release@example.invalid
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Key | What to write |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `destination` | The destination's GitHub `OWNER/REPO`, rather than a URL. The source repository itself is rejected. |
|
|
80
|
+
| `include` | Files to send, as a multiline string in `.gitignore` syntax. |
|
|
81
|
+
| `exclude` | Files to leave out, in the same syntax. If both lists match a file, `exclude` wins. |
|
|
82
|
+
| `word-list` | The forbidden-word file's path, relative to the repository root. The file must be inside the repository. |
|
|
83
|
+
| `author` | Optional `name` and `email`. Both the destination commit's author and committer use these values. Replace the example identity with yours. |
|
|
84
|
+
|
|
85
|
+
Every file in the tagged source tree must match `include` or `exclude`; a file in neither list stops the command. These lists classify tracked files in the tag, not untracked files in the working directory. Each list follows Git's `.gitignore` rules, including `#` comments, `!` negation, `/`-anchored paths, and `**`. Within a list, later matching rules take precedence. A negated child pattern cannot bring back a file while its parent directory remains excluded.
|
|
86
|
+
|
|
87
|
+
Keep the configuration and forbidden-word file in `exclude`, and add rules for any other tracked files in your repository. If you change `word-list`, update its exclusion too. All four required keys must be present; an explicitly empty `include` or `exclude` string is allowed, but every file still needs classification.
|
|
88
|
+
|
|
89
|
+
If you omit `author`, noren uses the authenticated [GitHub CLI](https://cli.github.com/) account when `gh` is available: its name (or username if the name is empty) and `ID+USERNAME@users.noreply.github.com`. If that account cannot be obtained, noren stops and asks you to configure `author.name` and `author.email`. `gh` is optional and only supplies this default identity; push authentication comes from Git.
|
|
90
|
+
|
|
91
|
+
For SSH authentication, you can configure Git to rewrite the GitHub HTTPS URLs inside this source repository:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
git config --local url."git@github.com:".insteadOf https://github.com/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Configure noren-words.txt
|
|
98
|
+
|
|
99
|
+
Write one forbidden word or phrase per line. The generated file already contains the source `origin` URL and its repository name. Keep those entries and add identifiers or text that must not appear in selected file contents. For example, with `origin` set to `git@github.com:OWNER/source-private.git`:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
git@github.com:OWNER/source-private.git
|
|
103
|
+
source-private
|
|
104
|
+
internal-project
|
|
105
|
+
private@example.invalid
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The list must contain at least one nonblank line. Every nonblank line is an entry, including a line beginning with `#`; the word list has no comment syntax. noren compares substrings after Unicode NFKC normalization and case folding, so case and full-width forms also match. Bytes that cannot be decoded as UTF-8 are replaced for the inspection. The files are sent with their original bytes.
|
|
109
|
+
|
|
110
|
+
### Commit the settings before selecting a tag
|
|
111
|
+
|
|
112
|
+
noren reads the selected files, `noren.yaml`, and the word list from the commit named by `--tag`. Changes in the working directory or later commits do not affect that tag's check or publication.
|
|
113
|
+
|
|
114
|
+
Commit the source files you intend to send, then commit the settings and create the source tag you will use:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
git add noren.yaml noren-words.txt
|
|
118
|
+
git commit -m "Configure noren"
|
|
119
|
+
git tag v1.0.0
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If you correct settings or file contents after a failed check, commit the correction and choose a tag that contains it before checking again.
|
|
123
|
+
|
|
124
|
+
## Check before sending
|
|
125
|
+
|
|
126
|
+
`noren publish` defaults to dry-run. Both `--tag` and `--message` are required, even for a check. For the first publication, when the destination has no `main` branch:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For a tag containing only `README.md` and `src/app.py` among the included files, a successful first check prints:
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
tag: v1.0.0
|
|
136
|
+
destination: OWNER/public-project
|
|
137
|
+
files:
|
|
138
|
+
- README.md
|
|
139
|
+
- src/app.py
|
|
140
|
+
destination_main_before: null
|
|
141
|
+
commit: null
|
|
142
|
+
pushed: false
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Check `destination` and every path in `files`. Dry-run creates no destination commit and updates no destination branches or tags, but it reads the destination's references, so Git access is needed. It also resolves the author identity. A successful dry-run does not guarantee permission to push.
|
|
146
|
+
|
|
147
|
+
The command exits with 0 if the check succeeds. It exits with a nonzero code and writes the reason to stderr if, for example, a file is in neither list, selected contents contain a forbidden word, a required setting or a nonempty word list is missing, or the destination cannot be read. Unclassified-file errors list paths; forbidden-word errors identify the file and line. Selected submodules must be excluded; symlinks are inspected using their link target text and sent as symlinks.
|
|
148
|
+
|
|
149
|
+
Use `--initial` only when destination `main` is absent, for both dry-run and push. noren stops if `--initial` is given and `main` already exists, or if `--initial` is omitted and `main` does not exist. An existing destination tag of the requested name also stops publication.
|
|
150
|
+
|
|
151
|
+
## Send the checked files
|
|
152
|
+
|
|
153
|
+
Add `--push` to the command you checked:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial --push
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The first publication creates a commit with no parent. Each later publication adds one commit whose only parent is the destination's previous `main` tip. Its tree contains exactly the selected source files; files absent from the selection are absent from the new destination tree. noren updates destination `main` and a tag with the source tag's name together in one atomic push, without force. The destination tag points directly to the new commit, even if the source tag is annotated.
|
|
160
|
+
|
|
161
|
+
For a later source tag, omit `--initial`:
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0"
|
|
165
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Choose a destination commit message appropriate for the files you are sending. noren uses that message instead of the source commit messages.
|
|
169
|
+
|
|
170
|
+
## Verify the result
|
|
171
|
+
|
|
172
|
+
`noren publish` writes one YAML document to stdout on success and failure. Save this document and stderr, and check the exit code. To save the output of the later push above, use this form in place of that push command:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push > /tmp/noren-result.yaml 2> /tmp/noren-error.txt
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
| Key | Meaning |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `tag` | The requested source tag name; an empty string if unavailable. |
|
|
181
|
+
| `destination` | The destination `OWNER/REPO`; an empty string if unavailable. |
|
|
182
|
+
| `files` | The selected file paths as a YAML list, possibly empty. This list alone does not indicate a successful check or push. |
|
|
183
|
+
| `destination_main_before` | The destination's `main` commit ID read before sending. `null` means the destination was read and `main` was absent; `''` means that value could not be obtained. |
|
|
184
|
+
| `commit` | The created destination commit ID. `null` for dry-run or a failure before creating a commit. |
|
|
185
|
+
| `pushed` | `true` when Git reported that destination `main` and the tag were updated; `false` for dry-run or when the command could not confirm a successful push. |
|
|
186
|
+
|
|
187
|
+
A successful push exits with 0 and has `pushed: true` and a non-null `commit`. The ID is the destination commit's ID, not the source commit's ID.
|
|
188
|
+
|
|
189
|
+
If a push fails or its result is uncertain and `commit` is non-null, keep that ID and `destination_main_before`. `pushed: false` by itself cannot establish whether the remote received the update. Read the destination references, replacing the example repository and tag with those in your result:
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
git ls-remote --refs https://github.com/OWNER/public-project.git refs/heads/main refs/tags/v1.1.0
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
If both references show the printed `commit` ID, the update is present. If `main` has advanced since then, a matching tag still identifies the published snapshot; check the destination history to confirm that commit is an ancestor of the current `main`. If `main` still equals `destination_main_before` and the tag is absent, the update is not present at the time of the check. If the references differ otherwise, inspect the destination history before deciding what to do. A failed `ls-remote` does not establish whether the push succeeded. Do not infer the result from the exit code alone or blindly repeat the initial command: existing `main` or an existing tag will stop it.
|
|
196
|
+
|
|
197
|
+
## Command help
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
uv run noren --help
|
|
201
|
+
uv run noren init --help
|
|
202
|
+
uv run noren publish --help
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Command help is in English. This README covers setup, checks, sending, and verification. Your project's version changes, builds, and publication to package registries belong to its own release instructions.
|
noren-0.1.0/README.ja.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# noren
|
|
2
|
+
|
|
3
|
+
[English](README.md)
|
|
4
|
+
|
|
5
|
+
noren は、Git リポジトリで選んだファイルを別のリポジトリへ一つの commit として送るコマンドです。パッケージのレジストリへの公開は行いません。
|
|
6
|
+
|
|
7
|
+
例えば、private のリポジトリから公開するファイルを選び、GitHub に送るために使います。送り先には、選んだファイル、指定した commit message、設定した author と committer が置かれます。元の commit、その message、注釈付き tag の message はコピーされません。選んだファイルの path と中身はコピーされます。
|
|
8
|
+
|
|
9
|
+
## インストールと実行方法
|
|
10
|
+
|
|
11
|
+
Python 3.12 以上、Git、[uv](https://docs.astral.sh/uv/) が必要です。コマンドは元の Git リポジトリの中で実行します。
|
|
12
|
+
|
|
13
|
+
Python プロジェクトの開発時の依存として noren を追加する場合:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
uv add --dev noren
|
|
17
|
+
uv run noren --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
プロジェクトの依存に追加せずに使う場合は、[uvx](https://docs.astral.sh/uv/guides/tools/) で隔離された実行環境から起動できます。
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
uvx noren --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
以下の例は `uv run noren` を使います。uvx を選んだ場合は、その部分を `uvx noren` に置き換えてください。すでに実行環境から noren を起動できる場合は、`noren` を直接使えます。`noren init` と `noren publish` は対話の入力を求めません。
|
|
27
|
+
|
|
28
|
+
## 初期セットアップ
|
|
29
|
+
|
|
30
|
+
元のリポジトリには remote の `origin` が必要です。GitHub に別の送り先リポジトリを作り、普段使っている Git の認証で読み取りと push ができるようにしてください。noren は、既存の Git の設定で `https://github.com/OWNER/REPO.git` にアクセスします。
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
uv run noren init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`noren init` は引数を取らず、元のリポジトリの root に `noren.yaml` と `noren-words.txt` を作ります。サブディレクトリから実行した場合も同じです。成功時は設定の案内を標準出力に出し、終了コード 0 で終わります。失敗時は理由を標準エラー出力に出し、0 以外で終わります。どちらかのファイルがすでにあれば上書きせずに止まり、`origin` が無い場合はどちらのファイルも作りません。
|
|
37
|
+
|
|
38
|
+
### noren.yaml を設定する
|
|
39
|
+
|
|
40
|
+
生成された雛形を編集します。次の例は `README.md`、`LICENSE`、`src/` の下のファイルを送り、`src/internal/` は外します。`OWNER/public-project` は送り先に置き換えてください。
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
destination: OWNER/public-project
|
|
44
|
+
include: |
|
|
45
|
+
README.md
|
|
46
|
+
LICENSE
|
|
47
|
+
src/
|
|
48
|
+
exclude: |
|
|
49
|
+
src/internal/
|
|
50
|
+
private/
|
|
51
|
+
tests/
|
|
52
|
+
.github/
|
|
53
|
+
.nf/
|
|
54
|
+
.gitignore
|
|
55
|
+
pyproject.toml
|
|
56
|
+
uv.lock
|
|
57
|
+
noren.yaml
|
|
58
|
+
noren-words.txt
|
|
59
|
+
word-list: noren-words.txt
|
|
60
|
+
author:
|
|
61
|
+
name: Release Bot
|
|
62
|
+
email: release@example.invalid
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| key | 書く内容 |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `destination` | 送り先の GitHub の `OWNER/REPO`。URL ではありません。元のリポジトリ自身を指定すると止まります。 |
|
|
68
|
+
| `include` | 送るファイルの一覧。`.gitignore` の書式のまま、複数行の文字列で書きます。 |
|
|
69
|
+
| `exclude` | 送らないファイルの一覧。同じ書式で書きます。両方の一覧に当たるファイルは `exclude` が優先されます。 |
|
|
70
|
+
| `word-list` | 禁止語の一覧のファイルの path。リポジトリの root からの相対 path で、リポジトリの中のファイルを指定します。 |
|
|
71
|
+
| `author` | 任意の `name` と `email`。送り先の commit の author と committer の両方に使います。例の値は利用する名義に置き換えてください。 |
|
|
72
|
+
|
|
73
|
+
元の tag の tree にあるファイルは、すべて `include` または `exclude` に当たる必要があります。どちらにも無いファイルがあると、コマンドは止まります。一覧の対象は tag に記録されたファイルで、working directory の未追跡のファイルは対象にしません。各一覧は Git の `.gitignore` の規則に従い、`#` の comment、`!` の否定、`/` による root への固定、`**` を使えます。同じ一覧の中では後に書いた一致する規則が優先されます。親のディレクトリが除外されたままでは、子のファイルを否定の pattern だけで戻すことはできません。
|
|
74
|
+
|
|
75
|
+
設定ファイルと禁止語の一覧のファイルは `exclude` に残し、リポジトリの他の追跡するファイルも一覧に加えてください。`word-list` を変えた場合は、そのファイルの除外も更新します。必須の四つの key はすべて必要です。`include` または `exclude` を空の文字列として設定することはできますが、どのファイルも分類する必要があります。
|
|
76
|
+
|
|
77
|
+
`author` を省いた場合、noren は [GitHub CLI](https://cli.github.com/) の `gh` が使える時に、認証済み account の名前 (名前が空なら username) と `ID+USERNAME@users.noreply.github.com` を使います。account を取得できない場合は止まり、`author.name` と `author.email` の設定を求めます。`gh` は任意で、この既定の名義を作るためだけに使います。push の認証は Git の設定を使います。
|
|
78
|
+
|
|
79
|
+
SSH の認証を使う場合は、この元のリポジトリの中で GitHub の HTTPS URL を書き換えるよう Git に設定できます。
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
git config --local url."git@github.com:".insteadOf https://github.com/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### noren-words.txt を設定する
|
|
86
|
+
|
|
87
|
+
禁止する語や文を一行に一つずつ書きます。生成されたファイルには、元の `origin` の URL とリポジトリの名前が入っています。その二つを残し、送るファイルの中身に含まれてはいけない識別子や文を加えてください。例えば、`origin` が `git@github.com:OWNER/source-private.git` の場合:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
git@github.com:OWNER/source-private.git
|
|
91
|
+
source-private
|
|
92
|
+
internal-project
|
|
93
|
+
private@example.invalid
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
一覧には空白でない行が一つ以上必要です。`#` で始まる行も含め、空白でない行はすべて禁止語になります。禁止語の一覧には comment の書式はありません。noren は Unicode の NFKC 正規化と case folding の後に部分一致で探すため、大文字と小文字の違い、全角の表記でも当たります。UTF-8 として読めない byte は、検査の際に置き換え文字として扱います。送るファイルの byte は元のままです。
|
|
97
|
+
|
|
98
|
+
### 設定を commit してから tag を指定する
|
|
99
|
+
|
|
100
|
+
noren は、`--tag` が指す commit から、送るファイル、`noren.yaml`、禁止語の一覧を読みます。working directory や後の commit で変更しても、その tag の検査や送信には反映されません。
|
|
101
|
+
|
|
102
|
+
送る予定の元のファイルを commit した後、設定を commit し、使う元の tag を作ります。
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
git add noren.yaml noren-words.txt
|
|
106
|
+
git commit -m "Configure noren"
|
|
107
|
+
git tag v1.0.0
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
検査で止まった後に設定やファイルの中身を直した場合は、修正を commit し、その修正を含む tag を選んでから、もう一度検査してください。
|
|
111
|
+
|
|
112
|
+
## 送る前に確認する
|
|
113
|
+
|
|
114
|
+
`noren publish` の既定の動作は dry-run です。検査の場合も `--tag` と `--message` は必須です。最初の一回で、送り先に `main` branch が無い場合:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
送る一覧に当たるファイルが `README.md` と `src/app.py` の二つだけの tag なら、最初の検査の成功時に次の結果を出します。
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
tag: v1.0.0
|
|
124
|
+
destination: OWNER/public-project
|
|
125
|
+
files:
|
|
126
|
+
- README.md
|
|
127
|
+
- src/app.py
|
|
128
|
+
destination_main_before: null
|
|
129
|
+
commit: null
|
|
130
|
+
pushed: false
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`destination` と `files` の各 path を確認してください。dry-run は送り先の commit を作らず、送り先の branch と tag を更新しません。ただし、送り先の参照を読むので、Git のアクセスが必要です。author の名義も確認します。dry-run の成功は push の権限を保証しません。
|
|
134
|
+
|
|
135
|
+
検査が成功すると、コマンドは終了コード 0 で終わります。どちらの一覧にも無いファイルがある場合、送る中身に禁止語がある場合、必須の設定や語を含む禁止語の一覧が無い場合、送り先を読めない場合などは、0 以外で終わり、理由を標準エラー出力に出します。未分類のファイルのエラーは path を示し、禁止語のエラーはファイルと行を示します。送る一覧に当たる submodule は除外する必要があります。symlink はリンク先の文字列を検査し、symlink のまま送ります。
|
|
136
|
+
|
|
137
|
+
dry-run と push のどちらも、送り先に `main` が無い時だけ `--initial` を使います。`--initial` があって `main` が存在する場合と、`--initial` が無く `main` が存在しない場合は止まります。送り先に指定した名前の tag がすでにある場合も止まります。
|
|
138
|
+
|
|
139
|
+
## 確認したファイルを送る
|
|
140
|
+
|
|
141
|
+
確認したコマンドに `--push` を加えます。
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial --push
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
最初の一回は、親の無い commit を作ります。次からは、送り先の直前の `main` の先端だけを親にした commit を一つ足します。その tree は選んだ元のファイルだけを持ち、選んだ一覧に無いファイルは新しい送り先の tree に残りません。noren は、送り先の `main` と元の tag と同じ名前の tag を、force を使わず、一回の atomic push で一緒に更新します。元の tag が注釈付きでも、送り先の tag は新しい commit を直接指します。
|
|
148
|
+
|
|
149
|
+
次の元の tag を送る時は `--initial` を外します。
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0"
|
|
153
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
送るファイルに合った送り先の commit message を指定してください。noren は元の commit message の代わりに、その message を使います。
|
|
157
|
+
|
|
158
|
+
## 送った結果を確かめる
|
|
159
|
+
|
|
160
|
+
`noren publish` は成功時も失敗時も、一つの YAML 文書を標準出力に出します。その文書と標準エラー出力を保存し、終了コードを確認してください。上の次回の push の出力を保存する場合は、その push のコマンドの代わりに次の形を使います。
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push > /tmp/noren-result.yaml 2> /tmp/noren-error.txt
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| key | 意味 |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `tag` | 指定した元の tag の名前。取得できない場合は空の文字列です。 |
|
|
169
|
+
| `destination` | 送り先の `OWNER/REPO`。取得できない場合は空の文字列です。 |
|
|
170
|
+
| `files` | 選んだファイルの path の YAML の list。空の場合もあります。この一覧だけでは検査や push の成功は分かりません。 |
|
|
171
|
+
| `destination_main_before` | 送る前に読んだ送り先の `main` の commit の ID。`null` は送り先を読めて `main` が無かった場合、`''` は値を取得できなかった場合です。 |
|
|
172
|
+
| `commit` | 作った送り先の commit の ID。dry-run の時と、commit を作る前に止めた時は `null` です。 |
|
|
173
|
+
| `pushed` | Git が送り先の `main` と tag の更新を成功と報告した場合は `true`。dry-run の時と、コマンドが push の成功を確認できなかった場合は `false` です。 |
|
|
174
|
+
|
|
175
|
+
push の成功時は終了コードが 0 で、`pushed: true` となり、`commit` は `null` 以外の値になります。この ID は送り先の commit の ID で、元の commit の ID ではありません。
|
|
176
|
+
|
|
177
|
+
push が失敗した場合や結果が不明な場合に、`commit` が `null` 以外なら、その ID と `destination_main_before` を残してください。`pushed: false` だけでは、送り先が更新を受け取ったかは決まりません。結果にあるリポジトリと tag に例を置き換え、送り先の参照を読みます。
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
git ls-remote --refs https://github.com/OWNER/public-project.git refs/heads/main refs/tags/v1.1.0
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
両方の参照が出力された `commit` の ID を示す場合、更新は送り先にあります。その後に `main` が進んだ場合も、tag が同じ ID なら送った時のファイルを特定できます。送り先の履歴を見て、その commit が現在の `main` の祖先かを確かめてください。`main` が `destination_main_before` のままで tag が無い場合、確認した時点では更新がありません。他の値になっている場合は、送り先の履歴を調べてから次の操作を決めてください。`ls-remote` の失敗では、push の成否は分かりません。終了コードだけで結果を決めたり、初回のコマンドをそのまま繰り返したりしないでください。すでに `main` や tag があれば、コマンドは止まります。
|
|
184
|
+
|
|
185
|
+
## コマンドの help
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
uv run noren --help
|
|
189
|
+
uv run noren init --help
|
|
190
|
+
uv run noren publish --help
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
コマンドの help は英語です。この README は初期セットアップ、検査、送信、結果の確認を扱います。プロジェクトの version の変更、build、パッケージのレジストリへの公開は、そのプロジェクトの release の手順を参照してください。
|
noren-0.1.0/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# noren
|
|
2
|
+
|
|
3
|
+
[日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
noren sends selected files from one Git repository to another as a single commit; it does not publish packages to a registry.
|
|
6
|
+
|
|
7
|
+
Use it, for example, to send a public snapshot of a private repository to GitHub. The destination receives the selected files, the commit message you supply, and the configured author and committer. Source commits, their messages, and annotated-tag messages are not copied. File paths and file contents that you select are copied.
|
|
8
|
+
|
|
9
|
+
## Install and choose how to run
|
|
10
|
+
|
|
11
|
+
You need Python 3.12 or later, Git, and [uv](https://docs.astral.sh/uv/). Run commands inside the source Git repository.
|
|
12
|
+
|
|
13
|
+
Add noren as a development dependency of your Python project:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
uv add --dev noren
|
|
17
|
+
uv run noren --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Alternatively, [uvx](https://docs.astral.sh/uv/guides/tools/) runs noren in an isolated environment without adding it to your project's dependencies:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
uvx noren --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The examples below use `uv run noren`. If you chose uvx, replace that prefix with `uvx noren`. If noren is already available in your environment, you can use `noren` directly. `noren init` and `noren publish` work without interactive input.
|
|
27
|
+
|
|
28
|
+
## Initial setup
|
|
29
|
+
|
|
30
|
+
The source repository must have an `origin` remote. Create a separate destination repository on GitHub and make sure your usual Git authentication can read it and push to it. noren uses `https://github.com/OWNER/REPO.git`, with your existing Git configuration.
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
uv run noren init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`noren init` takes no arguments and creates `noren.yaml` and `noren-words.txt` at the source repository root, even when run from a subdirectory. It prints setup instructions, exits with 0 on success, and reports errors to stderr with a nonzero exit code. It refuses to overwrite either file and creates neither file if `origin` is missing.
|
|
37
|
+
|
|
38
|
+
### Configure noren.yaml
|
|
39
|
+
|
|
40
|
+
Edit the generated template. This example sends `README.md`, `LICENSE`, and files under `src/`, except `src/internal/`. Replace `OWNER/public-project` with your destination:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
destination: OWNER/public-project
|
|
44
|
+
include: |
|
|
45
|
+
README.md
|
|
46
|
+
LICENSE
|
|
47
|
+
src/
|
|
48
|
+
exclude: |
|
|
49
|
+
src/internal/
|
|
50
|
+
private/
|
|
51
|
+
tests/
|
|
52
|
+
.github/
|
|
53
|
+
.nf/
|
|
54
|
+
.gitignore
|
|
55
|
+
pyproject.toml
|
|
56
|
+
uv.lock
|
|
57
|
+
noren.yaml
|
|
58
|
+
noren-words.txt
|
|
59
|
+
word-list: noren-words.txt
|
|
60
|
+
author:
|
|
61
|
+
name: Release Bot
|
|
62
|
+
email: release@example.invalid
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| Key | What to write |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `destination` | The destination's GitHub `OWNER/REPO`, rather than a URL. The source repository itself is rejected. |
|
|
68
|
+
| `include` | Files to send, as a multiline string in `.gitignore` syntax. |
|
|
69
|
+
| `exclude` | Files to leave out, in the same syntax. If both lists match a file, `exclude` wins. |
|
|
70
|
+
| `word-list` | The forbidden-word file's path, relative to the repository root. The file must be inside the repository. |
|
|
71
|
+
| `author` | Optional `name` and `email`. Both the destination commit's author and committer use these values. Replace the example identity with yours. |
|
|
72
|
+
|
|
73
|
+
Every file in the tagged source tree must match `include` or `exclude`; a file in neither list stops the command. These lists classify tracked files in the tag, not untracked files in the working directory. Each list follows Git's `.gitignore` rules, including `#` comments, `!` negation, `/`-anchored paths, and `**`. Within a list, later matching rules take precedence. A negated child pattern cannot bring back a file while its parent directory remains excluded.
|
|
74
|
+
|
|
75
|
+
Keep the configuration and forbidden-word file in `exclude`, and add rules for any other tracked files in your repository. If you change `word-list`, update its exclusion too. All four required keys must be present; an explicitly empty `include` or `exclude` string is allowed, but every file still needs classification.
|
|
76
|
+
|
|
77
|
+
If you omit `author`, noren uses the authenticated [GitHub CLI](https://cli.github.com/) account when `gh` is available: its name (or username if the name is empty) and `ID+USERNAME@users.noreply.github.com`. If that account cannot be obtained, noren stops and asks you to configure `author.name` and `author.email`. `gh` is optional and only supplies this default identity; push authentication comes from Git.
|
|
78
|
+
|
|
79
|
+
For SSH authentication, you can configure Git to rewrite the GitHub HTTPS URLs inside this source repository:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
git config --local url."git@github.com:".insteadOf https://github.com/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Configure noren-words.txt
|
|
86
|
+
|
|
87
|
+
Write one forbidden word or phrase per line. The generated file already contains the source `origin` URL and its repository name. Keep those entries and add identifiers or text that must not appear in selected file contents. For example, with `origin` set to `git@github.com:OWNER/source-private.git`:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
git@github.com:OWNER/source-private.git
|
|
91
|
+
source-private
|
|
92
|
+
internal-project
|
|
93
|
+
private@example.invalid
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The list must contain at least one nonblank line. Every nonblank line is an entry, including a line beginning with `#`; the word list has no comment syntax. noren compares substrings after Unicode NFKC normalization and case folding, so case and full-width forms also match. Bytes that cannot be decoded as UTF-8 are replaced for the inspection. The files are sent with their original bytes.
|
|
97
|
+
|
|
98
|
+
### Commit the settings before selecting a tag
|
|
99
|
+
|
|
100
|
+
noren reads the selected files, `noren.yaml`, and the word list from the commit named by `--tag`. Changes in the working directory or later commits do not affect that tag's check or publication.
|
|
101
|
+
|
|
102
|
+
Commit the source files you intend to send, then commit the settings and create the source tag you will use:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
git add noren.yaml noren-words.txt
|
|
106
|
+
git commit -m "Configure noren"
|
|
107
|
+
git tag v1.0.0
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If you correct settings or file contents after a failed check, commit the correction and choose a tag that contains it before checking again.
|
|
111
|
+
|
|
112
|
+
## Check before sending
|
|
113
|
+
|
|
114
|
+
`noren publish` defaults to dry-run. Both `--tag` and `--message` are required, even for a check. For the first publication, when the destination has no `main` branch:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For a tag containing only `README.md` and `src/app.py` among the included files, a successful first check prints:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
tag: v1.0.0
|
|
124
|
+
destination: OWNER/public-project
|
|
125
|
+
files:
|
|
126
|
+
- README.md
|
|
127
|
+
- src/app.py
|
|
128
|
+
destination_main_before: null
|
|
129
|
+
commit: null
|
|
130
|
+
pushed: false
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Check `destination` and every path in `files`. Dry-run creates no destination commit and updates no destination branches or tags, but it reads the destination's references, so Git access is needed. It also resolves the author identity. A successful dry-run does not guarantee permission to push.
|
|
134
|
+
|
|
135
|
+
The command exits with 0 if the check succeeds. It exits with a nonzero code and writes the reason to stderr if, for example, a file is in neither list, selected contents contain a forbidden word, a required setting or a nonempty word list is missing, or the destination cannot be read. Unclassified-file errors list paths; forbidden-word errors identify the file and line. Selected submodules must be excluded; symlinks are inspected using their link target text and sent as symlinks.
|
|
136
|
+
|
|
137
|
+
Use `--initial` only when destination `main` is absent, for both dry-run and push. noren stops if `--initial` is given and `main` already exists, or if `--initial` is omitted and `main` does not exist. An existing destination tag of the requested name also stops publication.
|
|
138
|
+
|
|
139
|
+
## Send the checked files
|
|
140
|
+
|
|
141
|
+
Add `--push` to the command you checked:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
uv run noren publish --tag v1.0.0 --message "Release v1.0.0" --initial --push
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The first publication creates a commit with no parent. Each later publication adds one commit whose only parent is the destination's previous `main` tip. Its tree contains exactly the selected source files; files absent from the selection are absent from the new destination tree. noren updates destination `main` and a tag with the source tag's name together in one atomic push, without force. The destination tag points directly to the new commit, even if the source tag is annotated.
|
|
148
|
+
|
|
149
|
+
For a later source tag, omit `--initial`:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0"
|
|
153
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Choose a destination commit message appropriate for the files you are sending. noren uses that message instead of the source commit messages.
|
|
157
|
+
|
|
158
|
+
## Verify the result
|
|
159
|
+
|
|
160
|
+
`noren publish` writes one YAML document to stdout on success and failure. Save this document and stderr, and check the exit code. To save the output of the later push above, use this form in place of that push command:
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
uv run noren publish --tag v1.1.0 --message "Release v1.1.0" --push > /tmp/noren-result.yaml 2> /tmp/noren-error.txt
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Key | Meaning |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `tag` | The requested source tag name; an empty string if unavailable. |
|
|
169
|
+
| `destination` | The destination `OWNER/REPO`; an empty string if unavailable. |
|
|
170
|
+
| `files` | The selected file paths as a YAML list, possibly empty. This list alone does not indicate a successful check or push. |
|
|
171
|
+
| `destination_main_before` | The destination's `main` commit ID read before sending. `null` means the destination was read and `main` was absent; `''` means that value could not be obtained. |
|
|
172
|
+
| `commit` | The created destination commit ID. `null` for dry-run or a failure before creating a commit. |
|
|
173
|
+
| `pushed` | `true` when Git reported that destination `main` and the tag were updated; `false` for dry-run or when the command could not confirm a successful push. |
|
|
174
|
+
|
|
175
|
+
A successful push exits with 0 and has `pushed: true` and a non-null `commit`. The ID is the destination commit's ID, not the source commit's ID.
|
|
176
|
+
|
|
177
|
+
If a push fails or its result is uncertain and `commit` is non-null, keep that ID and `destination_main_before`. `pushed: false` by itself cannot establish whether the remote received the update. Read the destination references, replacing the example repository and tag with those in your result:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
git ls-remote --refs https://github.com/OWNER/public-project.git refs/heads/main refs/tags/v1.1.0
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If both references show the printed `commit` ID, the update is present. If `main` has advanced since then, a matching tag still identifies the published snapshot; check the destination history to confirm that commit is an ancestor of the current `main`. If `main` still equals `destination_main_before` and the tag is absent, the update is not present at the time of the check. If the references differ otherwise, inspect the destination history before deciding what to do. A failed `ls-remote` does not establish whether the push succeeded. Do not infer the result from the exit code alone or blindly repeat the initial command: existing `main` or an existing tag will stop it.
|
|
184
|
+
|
|
185
|
+
## Command help
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
uv run noren --help
|
|
189
|
+
uv run noren init --help
|
|
190
|
+
uv run noren publish --help
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Command help is in English. This README covers setup, checks, sending, and verification. Your project's version changes, builds, and publication to package registries belong to its own release instructions.
|