pyinfra-incus 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.
Files changed (55) hide show
  1. pyinfra_incus-0.1.0/.github/scripts/validate-release.py +84 -0
  2. pyinfra_incus-0.1.0/.github/workflows/ci.yml +47 -0
  3. pyinfra_incus-0.1.0/.github/workflows/integration.yml +122 -0
  4. pyinfra_incus-0.1.0/.github/workflows/release-dry-run.yml +48 -0
  5. pyinfra_incus-0.1.0/.github/workflows/release-please.yml +36 -0
  6. pyinfra_incus-0.1.0/.github/workflows/release.yml +113 -0
  7. pyinfra_incus-0.1.0/.gitignore +17 -0
  8. pyinfra_incus-0.1.0/.moon/toolchains.yml +2 -0
  9. pyinfra_incus-0.1.0/.moon/workspace.yml +12 -0
  10. pyinfra_incus-0.1.0/.python-version +1 -0
  11. pyinfra_incus-0.1.0/.release-please-manifest.json +1 -0
  12. pyinfra_incus-0.1.0/.session.md +233 -0
  13. pyinfra_incus-0.1.0/AGENTS.md +13 -0
  14. pyinfra_incus-0.1.0/CHANGELOG.md +21 -0
  15. pyinfra_incus-0.1.0/CLAUDE.md +1 -0
  16. pyinfra_incus-0.1.0/PKG-INFO +8 -0
  17. pyinfra_incus-0.1.0/mise.lock +109 -0
  18. pyinfra_incus-0.1.0/mise.toml +36 -0
  19. pyinfra_incus-0.1.0/moon.yml +111 -0
  20. pyinfra_incus-0.1.0/pyproject.toml +66 -0
  21. pyinfra_incus-0.1.0/release-please-config.json +24 -0
  22. pyinfra_incus-0.1.0/src/pyinfra_incus/__init__.py +75 -0
  23. pyinfra_incus-0.1.0/src/pyinfra_incus/_client.py +113 -0
  24. pyinfra_incus-0.1.0/src/pyinfra_incus/_control_plane.py +313 -0
  25. pyinfra_incus-0.1.0/src/pyinfra_incus/_fact.py +158 -0
  26. pyinfra_incus-0.1.0/src/pyinfra_incus/_images.py +347 -0
  27. pyinfra_incus-0.1.0/src/pyinfra_incus/_instances.py +657 -0
  28. pyinfra_incus-0.1.0/src/pyinfra_incus/_network.py +239 -0
  29. pyinfra_incus-0.1.0/src/pyinfra_incus/_network_policy.py +457 -0
  30. pyinfra_incus-0.1.0/src/pyinfra_incus/_operational.py +149 -0
  31. pyinfra_incus-0.1.0/src/pyinfra_incus/_scope.py +391 -0
  32. pyinfra_incus-0.1.0/src/pyinfra_incus/_storage.py +415 -0
  33. pyinfra_incus-0.1.0/src/pyinfra_incus/facts.py +520 -0
  34. pyinfra_incus-0.1.0/src/pyinfra_incus/operations.py +1059 -0
  35. pyinfra_incus-0.1.0/src/pyinfra_incus/py.typed +0 -0
  36. pyinfra_incus-0.1.0/tests/conftest.py +31 -0
  37. pyinfra_incus-0.1.0/tests/integration/test_control_plane_workflow.py +228 -0
  38. pyinfra_incus-0.1.0/tests/integration/test_foundation_workflow.py +361 -0
  39. pyinfra_incus-0.1.0/tests/integration/test_image_workflow.py +160 -0
  40. pyinfra_incus-0.1.0/tests/integration/test_instance_workflow.py +306 -0
  41. pyinfra_incus-0.1.0/tests/integration/test_policy_workflow.py +248 -0
  42. pyinfra_incus-0.1.0/tests/integration/test_scope_workflow.py +283 -0
  43. pyinfra_incus-0.1.0/tests/integration/test_server.py +35 -0
  44. pyinfra_incus-0.1.0/tests/integration/test_snapshot_health_workflow.py +176 -0
  45. pyinfra_incus-0.1.0/tests/test_client.py +78 -0
  46. pyinfra_incus-0.1.0/tests/test_control_plane.py +129 -0
  47. pyinfra_incus-0.1.0/tests/test_facts.py +211 -0
  48. pyinfra_incus-0.1.0/tests/test_images.py +106 -0
  49. pyinfra_incus-0.1.0/tests/test_instances.py +205 -0
  50. pyinfra_incus-0.1.0/tests/test_network.py +99 -0
  51. pyinfra_incus-0.1.0/tests/test_network_policy.py +124 -0
  52. pyinfra_incus-0.1.0/tests/test_operational.py +93 -0
  53. pyinfra_incus-0.1.0/tests/test_scope.py +137 -0
  54. pyinfra_incus-0.1.0/tests/test_storage.py +88 -0
  55. pyinfra_incus-0.1.0/uv.lock +1245 -0
@@ -0,0 +1,84 @@
1
+ """Validate the built distributions before a registry upload."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import email
6
+ import pathlib
7
+ import sys
8
+ import tarfile
9
+ import zipfile
10
+ from email.message import Message
11
+
12
+ DIST = pathlib.Path("dist")
13
+ PACKAGE_NAME = "pyinfra-incus"
14
+
15
+
16
+ def fail(message: str) -> None:
17
+ raise SystemExit(message)
18
+
19
+
20
+ def metadata_from_wheel(path: pathlib.Path) -> Message:
21
+ with zipfile.ZipFile(path) as archive:
22
+ metadata_files = [
23
+ name for name in archive.namelist() if name.endswith(".dist-info/METADATA")
24
+ ]
25
+ if len(metadata_files) != 1:
26
+ fail(f"expected one METADATA file in {path}, found {len(metadata_files)}")
27
+ return email.message_from_bytes(archive.read(metadata_files[0]))
28
+
29
+
30
+ def metadata_from_sdist(path: pathlib.Path) -> Message:
31
+ with tarfile.open(path, "r:gz") as archive:
32
+ metadata_files = [
33
+ member for member in archive.getmembers() if member.name.endswith("/PKG-INFO")
34
+ ]
35
+ if len(metadata_files) != 1:
36
+ fail(f"expected one PKG-INFO file in {path}, found {len(metadata_files)}")
37
+ metadata_file = archive.extractfile(metadata_files[0])
38
+ if metadata_file is None:
39
+ fail(f"could not read PKG-INFO from {path}")
40
+ return email.message_from_bytes(metadata_file.read())
41
+
42
+
43
+ def validate_metadata(metadata: Message, expected_version: str | None) -> str:
44
+ name = metadata.get("Name")
45
+ version = metadata.get("Version")
46
+ if name != PACKAGE_NAME:
47
+ fail(f"expected package name {PACKAGE_NAME!r}, got {name!r}")
48
+ if not version:
49
+ fail("distribution metadata has no version")
50
+ if expected_version is not None and version != expected_version:
51
+ fail(f"tag version {expected_version!r} does not match package version {version!r}")
52
+
53
+ direct_references = [
54
+ requirement for requirement in metadata.get_all("Requires-Dist", []) if " @ " in requirement
55
+ ]
56
+ if direct_references:
57
+ rendered = "\n".join(f"- {requirement}" for requirement in direct_references)
58
+ fail(f"public package indexes reject direct dependency references:\n{rendered}")
59
+
60
+ return version
61
+
62
+
63
+ def main() -> None:
64
+ expected_version = sys.argv[1] if len(sys.argv) == 2 else None
65
+ if len(sys.argv) > 2:
66
+ fail("usage: validate-release.py [expected-version]")
67
+
68
+ wheels = sorted(DIST.glob("*.whl"))
69
+ sdists = sorted(DIST.glob("*.tar.gz"))
70
+ if len(wheels) != 1 or len(sdists) != 1:
71
+ fail(
72
+ f"expected one wheel and one sdist, found {len(wheels)} wheel(s) and {len(sdists)} sdist(s)"
73
+ )
74
+
75
+ wheel_version = validate_metadata(metadata_from_wheel(wheels[0]), expected_version)
76
+ sdist_version = validate_metadata(metadata_from_sdist(sdists[0]), expected_version)
77
+ if wheel_version != sdist_version:
78
+ fail(f"wheel version {wheel_version!r} does not match sdist version {sdist_version!r}")
79
+
80
+ print(f"validated {PACKAGE_NAME} {wheel_version}: {wheels[0].name}, {sdists[0].name}")
81
+
82
+
83
+ if __name__ == "__main__":
84
+ main()
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [master]
6
+ push:
7
+ branches: [master]
8
+
9
+ permissions: {}
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ ci:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ permissions:
20
+ contents: read
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
24
+ with:
25
+ fetch-depth: 0
26
+ persist-credentials: false
27
+
28
+ - name: Setup mise
29
+ uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
30
+ with:
31
+ version: 2026.6.14
32
+ cache: true
33
+
34
+ - name: Resolve uv cache directory
35
+ id: uv-cache
36
+ run: echo "dir=$(uv cache dir)" >> "$GITHUB_OUTPUT"
37
+
38
+ - name: Cache uv downloads
39
+ uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
40
+ with:
41
+ path: ${{ steps.uv-cache.outputs.dir }}
42
+ key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}
43
+ restore-keys: |
44
+ ${{ runner.os }}-uv-
45
+
46
+ - name: Run Moon CI
47
+ run: moon ci root:check --summary minimal
@@ -0,0 +1,122 @@
1
+ name: Integration
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [master]
6
+ push:
7
+ branches: [master]
8
+ workflow_dispatch:
9
+
10
+ permissions: {}
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ incus:
18
+ name: Incus ${{ matrix.label }}
19
+ runs-on: ubuntu-24.04
20
+ timeout-minutes: 25
21
+ permissions:
22
+ contents: read
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ include:
27
+ - label: 7.0 LTS
28
+ repository: lts-7.0
29
+ package_pattern: '1:7.0.*'
30
+ - label: stable
31
+ repository: stable
32
+ package_pattern: '1:7.*'
33
+ env:
34
+ INCUS_REPOSITORY: ${{ matrix.repository }}
35
+ INCUS_PACKAGE_PATTERN: ${{ matrix.package_pattern }}
36
+ PYINFRA_INCUS_TEST_SOCKET: /var/lib/incus/unix.socket
37
+ steps:
38
+ - name: Checkout
39
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
40
+ with:
41
+ fetch-depth: 0
42
+ persist-credentials: false
43
+
44
+ - name: Setup mise
45
+ uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
46
+ with:
47
+ version: 2026.6.14
48
+ cache: true
49
+
50
+ - name: Resolve uv cache directory
51
+ id: uv-cache
52
+ run: echo "dir=$(uv cache dir)" >> "$GITHUB_OUTPUT"
53
+
54
+ - name: Cache uv downloads
55
+ uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
56
+ with:
57
+ path: ${{ steps.uv-cache.outputs.dir }}
58
+ key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}
59
+ restore-keys: |
60
+ ${{ runner.os }}-uv-
61
+
62
+ - name: Check KVM availability
63
+ run: test -c /dev/kvm
64
+
65
+ - name: Isolate Incus client configuration
66
+ run: echo "INCUS_CONF=$RUNNER_TEMP/incus-user" >> "$GITHUB_ENV"
67
+
68
+ - name: Configure Zabbly package repository
69
+ run: |
70
+ curl -fsSL https://pkgs.zabbly.com/key.asc -o "$RUNNER_TEMP/zabbly.asc"
71
+ fingerprint=$(gpg --show-keys --with-colons "$RUNNER_TEMP/zabbly.asc" | awk -F: '$1 == "fpr" { print $10; exit }')
72
+ test "$fingerprint" = "4EFC590696CB15B87C73A3AD82CC8797C838DCFD"
73
+
74
+ sudo install -d -m 0755 /etc/apt/keyrings
75
+ sudo install -m 0644 "$RUNNER_TEMP/zabbly.asc" /etc/apt/keyrings/zabbly.asc
76
+ printf '%s\n' \
77
+ 'Enabled: yes' \
78
+ 'Types: deb' \
79
+ "URIs: https://pkgs.zabbly.com/incus/${INCUS_REPOSITORY}" \
80
+ 'Suites: noble' \
81
+ 'Components: main' \
82
+ 'Architectures: amd64' \
83
+ 'Signed-By: /etc/apt/keyrings/zabbly.asc' \
84
+ | sudo tee /etc/apt/sources.list.d/zabbly-incus.sources >/dev/null
85
+
86
+ - name: Install Incus
87
+ run: |
88
+ sudo apt-get update
89
+ sudo apt-get install -y acl incus incus-agent qemu-system-x86 qemu-utils ovmf virtiofsd
90
+
91
+ package_version=$(dpkg-query -W -f='${Version}' incus)
92
+ echo "Incus package: $package_version"
93
+ case "$package_version" in
94
+ $INCUS_PACKAGE_PATTERN) ;;
95
+ *)
96
+ echo "::error::Unexpected Incus package version: $package_version"
97
+ exit 1
98
+ ;;
99
+ esac
100
+
101
+ sudo env INCUS_CONF=/root/.config/incus incus admin init --minimal
102
+ sudo env INCUS_CONF=/root/.config/incus incus image copy images:alpine/edge/amd64 local: --alias ci-base
103
+ sudo env INCUS_CONF=/root/.config/incus incus version
104
+ uv run --locked python -c 'from importlib.metadata import version; print("pyincusd", version("pyincusd"))'
105
+
106
+ sudo test -S "$PYINFRA_INCUS_TEST_SOCKET"
107
+ sudo setfacl -m "u:${USER}:rw" "$PYINFRA_INCUS_TEST_SOCKET"
108
+ incus image info images:alpine/3.23/amd64 >/dev/null
109
+ incus image info images:alpine/3.23/amd64 --vm >/dev/null
110
+
111
+ - name: Run Incus integration tests
112
+ run: moon run root:test-integration --summary minimal
113
+
114
+ - name: Diagnostics on failure
115
+ if: failure()
116
+ run: |
117
+ sudo env INCUS_CONF=/root/.config/incus incus list || true
118
+ sudo env INCUS_CONF=/root/.config/incus incus image list || true
119
+ sudo env INCUS_CONF=/root/.config/incus incus storage list || true
120
+ sudo env INCUS_CONF=/root/.config/incus incus network list || true
121
+ sudo journalctl -u incus --no-pager -n 200 || true
122
+ df -h || true
@@ -0,0 +1,48 @@
1
+ # Rehearse the publishable package on Release Please PRs without uploading it.
2
+ # Keeping the trigger broad ensures the check still reports as skipped on
3
+ # ordinary pull requests.
4
+
5
+ name: Release Dry Run
6
+
7
+ on:
8
+ pull_request:
9
+ branches:
10
+ - master
11
+ workflow_dispatch:
12
+
13
+ permissions: {}
14
+
15
+ jobs:
16
+ package-release-dry-run:
17
+ name: Package Release Dry Run
18
+ if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please--') }}
19
+ runs-on: ubuntu-24.04
20
+ permissions:
21
+ contents: read
22
+ steps:
23
+ - name: Check out repository
24
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
25
+ with:
26
+ fetch-depth: 0
27
+ persist-credentials: false
28
+
29
+ - name: Setup mise
30
+ uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
31
+ with:
32
+ version: 2026.6.14
33
+ cache: true
34
+
35
+ - name: Build publishable distributions
36
+ run: uv build --no-sources --clear
37
+
38
+ - name: Validate distribution metadata
39
+ run: python3 .github/scripts/validate-release.py
40
+
41
+ - name: Smoke test installed wheel
42
+ run: |
43
+ wheel=$(find dist -maxdepth 1 -name '*.whl' -print -quit)
44
+ uv run --no-project --with "$wheel" -- \
45
+ python -c 'import pyinfra_incus; from importlib.metadata import version; print(version("pyinfra-incus"))'
46
+
47
+ - name: Rehearse registry upload
48
+ run: uv publish --dry-run dist/*
@@ -0,0 +1,36 @@
1
+ # Required release app settings:
2
+ # - vars.MEIGMA_RELEASE_APP_ID
3
+ # - secrets.MEIGMA_RELEASE_APP_PRIVATE_KEY
4
+
5
+ name: Release Please
6
+
7
+ on:
8
+ push:
9
+ branches:
10
+ - master
11
+ workflow_dispatch:
12
+
13
+ permissions: {}
14
+
15
+ jobs:
16
+ release-please:
17
+ name: Release Please
18
+ runs-on: ubuntu-24.04
19
+ permissions:
20
+ contents: write
21
+ pull-requests: write
22
+ issues: write
23
+ steps:
24
+ - name: Create release app token
25
+ id: release-app
26
+ uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
27
+ with:
28
+ app-id: ${{ vars.MEIGMA_RELEASE_APP_ID }}
29
+ private-key: ${{ secrets.MEIGMA_RELEASE_APP_PRIVATE_KEY }}
30
+
31
+ - name: Run Release Please
32
+ uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
33
+ with:
34
+ token: ${{ steps.release-app.outputs.token }}
35
+ config-file: release-please-config.json
36
+ manifest-file: .release-please-manifest.json
@@ -0,0 +1,113 @@
1
+ # Release Please creates the tag and a draft GitHub release. This workflow
2
+ # independently rebuilds the tagged source and publishes it to PyPI through
3
+ # Trusted Publishing. The GitHub release remains a draft for human inspection.
4
+
5
+ name: Release
6
+
7
+ on:
8
+ push:
9
+ tags:
10
+ - v*
11
+ workflow_dispatch:
12
+ inputs:
13
+ tag:
14
+ description: Tag to publish
15
+ required: true
16
+ type: string
17
+
18
+ permissions: {}
19
+
20
+ jobs:
21
+ resolve-release:
22
+ name: Resolve Release
23
+ runs-on: ubuntu-24.04
24
+ permissions:
25
+ contents: read
26
+ outputs:
27
+ tag: ${{ steps.release-tag.outputs.tag }}
28
+ version: ${{ steps.release-tag.outputs.version }}
29
+ steps:
30
+ - name: Resolve release tag
31
+ id: release-tag
32
+ env:
33
+ DISPATCH_TAG: ${{ inputs.tag }}
34
+ run: |
35
+ set -euo pipefail
36
+
37
+ if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
38
+ tag="$DISPATCH_TAG"
39
+ else
40
+ tag="$GITHUB_REF_NAME"
41
+ fi
42
+
43
+ if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.-]*)?$ ]]; then
44
+ echo "Release tag must match vX.Y.Z or vX.Y.Z-prerelease: $tag" >&2
45
+ exit 1
46
+ fi
47
+
48
+ echo "tag=$tag" >> "$GITHUB_OUTPUT"
49
+ echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
50
+
51
+ - name: Wait for draft release
52
+ env:
53
+ GH_TOKEN: ${{ github.token }}
54
+ RELEASE_TAG: ${{ steps.release-tag.outputs.tag }}
55
+ run: |
56
+ for attempt in $(seq 1 30); do
57
+ if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --json isDraft --jq '.isDraft' 2>/dev/null | grep -qx true; then
58
+ exit 0
59
+ fi
60
+ echo "Draft release $RELEASE_TAG is not ready yet; retrying..."
61
+ sleep 10
62
+ done
63
+
64
+ echo "Draft release $RELEASE_TAG was not found or is not a draft." >&2
65
+ exit 1
66
+
67
+ publish-pypi:
68
+ name: Publish to PyPI
69
+ needs:
70
+ - resolve-release
71
+ runs-on: ubuntu-24.04
72
+ environment: pypi
73
+ permissions:
74
+ contents: read
75
+ id-token: write
76
+ steps:
77
+ - name: Check out repository
78
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
79
+ with:
80
+ fetch-depth: 0
81
+ persist-credentials: false
82
+
83
+ - name: Check out requested tag
84
+ if: ${{ github.event_name == 'workflow_dispatch' }}
85
+ env:
86
+ RELEASE_TAG: ${{ needs.resolve-release.outputs.tag }}
87
+ run: git checkout --detach "$RELEASE_TAG"
88
+
89
+ - name: Setup mise
90
+ uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
91
+ with:
92
+ version: 2026.6.14
93
+ cache: false
94
+
95
+ - name: Run release quality gates
96
+ run: moon run root:check --summary minimal
97
+
98
+ - name: Build publishable distributions
99
+ run: uv build --no-sources --clear
100
+
101
+ - name: Validate distribution metadata
102
+ env:
103
+ RELEASE_VERSION: ${{ needs.resolve-release.outputs.version }}
104
+ run: python3 .github/scripts/validate-release.py "$RELEASE_VERSION"
105
+
106
+ - name: Smoke test installed wheel
107
+ run: |
108
+ wheel=$(find dist -maxdepth 1 -name '*.whl' -print -quit)
109
+ uv run --no-project --with "$wheel" -- \
110
+ python -c 'import pyinfra_incus; from importlib.metadata import version; print(version("pyinfra-incus"))'
111
+
112
+ - name: Publish distributions
113
+ run: uv publish --trusted-publishing always dist/*
@@ -0,0 +1,17 @@
1
+ .agents/
2
+ .claude/
3
+ .journal/
4
+ .wt/
5
+
6
+ .moon/cache/
7
+ .moon/docker/
8
+
9
+ .venv/
10
+ __pycache__/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ *.py[cod]
15
+ build/
16
+ dist/
17
+ *.egg-info/
@@ -0,0 +1,2 @@
1
+ # Tool versions are managed by mise.toml and mise.lock. Tasks use the system
2
+ # toolchain so Moon never installs a second Python or uv runtime.
@@ -0,0 +1,12 @@
1
+ projects:
2
+ root: '.'
3
+
4
+ defaultProject: 'root'
5
+
6
+ vcs:
7
+ defaultBranch: 'master'
8
+ provider: 'github'
9
+
10
+ # uv commands synchronize the locked environment explicitly inside each task.
11
+ pipeline:
12
+ installDependencies: false
@@ -0,0 +1 @@
1
+ 3.11.14
@@ -0,0 +1 @@
1
+ {".":"0.1.0"}