drayage 0.2.6__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.
- drayage-0.2.6/.dockerignore +17 -0
- drayage-0.2.6/.github/dependabot.yml +21 -0
- drayage-0.2.6/.github/workflows/ci.yml +61 -0
- drayage-0.2.6/.github/workflows/live-validation.yml +45 -0
- drayage-0.2.6/.github/workflows/oci-conformance.yml +101 -0
- drayage-0.2.6/.github/workflows/real-registry.yml +39 -0
- drayage-0.2.6/.github/workflows/release.yml +270 -0
- drayage-0.2.6/.gitignore +4 -0
- drayage-0.2.6/.pre-commit-config.yaml +78 -0
- drayage-0.2.6/CHANGELOG.md +76 -0
- drayage-0.2.6/Cargo.lock +2722 -0
- drayage-0.2.6/Cargo.toml +40 -0
- drayage-0.2.6/Dockerfile +25 -0
- drayage-0.2.6/LICENSE +21 -0
- drayage-0.2.6/Makefile +35 -0
- drayage-0.2.6/PKG-INFO +17 -0
- drayage-0.2.6/README.md +272 -0
- drayage-0.2.6/SECURITY.md +30 -0
- drayage-0.2.6/config.example.toml +27 -0
- drayage-0.2.6/deploy/caddy/Caddyfile +15 -0
- drayage-0.2.6/deploy/docker-compose.yml +37 -0
- drayage-0.2.6/deploy/nginx/drayage.conf +28 -0
- drayage-0.2.6/deploy/systemd/drayage.service +39 -0
- drayage-0.2.6/docs/oci-conformance.md +75 -0
- drayage-0.2.6/docs/production.md +123 -0
- drayage-0.2.6/docs/reverse-proxy.md +53 -0
- drayage-0.2.6/docs/troubleshooting.md +89 -0
- drayage-0.2.6/docs/upgrades.md +79 -0
- drayage-0.2.6/drayage/__init__.py +10 -0
- drayage-0.2.6/drayage/__main__.py +49 -0
- drayage-0.2.6/drayage/py.typed +0 -0
- drayage-0.2.6/pyproject.toml +33 -0
- drayage-0.2.6/scripts/install_systemd.sh +99 -0
- drayage-0.2.6/scripts/resolve_oci_pull_fixture.py +79 -0
- drayage-0.2.6/scripts/run_oci_pull_conformance.sh +72 -0
- drayage-0.2.6/src/cache.rs +1428 -0
- drayage-0.2.6/src/config.rs +955 -0
- drayage-0.2.6/src/gen_ca.rs +183 -0
- drayage-0.2.6/src/handlers/blobs.rs +231 -0
- drayage-0.2.6/src/handlers/manifests.rs +662 -0
- drayage-0.2.6/src/handlers/mod.rs +3 -0
- drayage-0.2.6/src/handlers/version.rs +11 -0
- drayage-0.2.6/src/init.rs +407 -0
- drayage-0.2.6/src/lib.rs +160 -0
- drayage-0.2.6/src/main.rs +315 -0
- drayage-0.2.6/src/metrics.rs +1121 -0
- drayage-0.2.6/src/negative_cache.rs +166 -0
- drayage-0.2.6/src/registry.rs +320 -0
- drayage-0.2.6/src/server.rs +345 -0
- drayage-0.2.6/src/tls.rs +241 -0
- drayage-0.2.6/src/upstream.rs +1934 -0
- drayage-0.2.6/tests/integration.rs +3003 -0
- drayage-0.2.6/tests/real_registry.rs +395 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: cargo
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
|
|
8
|
+
- package-ecosystem: pip
|
|
9
|
+
directory: /
|
|
10
|
+
schedule:
|
|
11
|
+
interval: weekly
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: docker
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
17
|
+
|
|
18
|
+
- package-ecosystem: github-actions
|
|
19
|
+
directory: /
|
|
20
|
+
schedule:
|
|
21
|
+
interval: weekly
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
name: Lint
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install Rust
|
|
21
|
+
uses: dtolnay/rust-toolchain@stable
|
|
22
|
+
with:
|
|
23
|
+
components: rustfmt, clippy
|
|
24
|
+
|
|
25
|
+
- name: Run linting
|
|
26
|
+
run: make lint
|
|
27
|
+
|
|
28
|
+
test:
|
|
29
|
+
name: Test
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
|
|
34
|
+
- name: Install Rust
|
|
35
|
+
uses: dtolnay/rust-toolchain@stable
|
|
36
|
+
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: make test
|
|
39
|
+
|
|
40
|
+
docker-build:
|
|
41
|
+
name: Docker Build
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
|
|
46
|
+
- name: Build container image
|
|
47
|
+
run: make docker-build
|
|
48
|
+
|
|
49
|
+
all-checks-passed:
|
|
50
|
+
name: All checks passed
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
needs: [lint, test, docker-build]
|
|
53
|
+
if: always()
|
|
54
|
+
steps:
|
|
55
|
+
- name: Verify all checks passed
|
|
56
|
+
run: |
|
|
57
|
+
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]; then
|
|
58
|
+
echo "Some checks failed or were cancelled"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
echo "All checks passed"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Live Validation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
run_real_registry:
|
|
7
|
+
description: "Run live upstream registry tests"
|
|
8
|
+
type: boolean
|
|
9
|
+
default: true
|
|
10
|
+
run_oci_pull_conformance:
|
|
11
|
+
description: "Run OCI pull conformance"
|
|
12
|
+
type: boolean
|
|
13
|
+
default: true
|
|
14
|
+
schedule:
|
|
15
|
+
- cron: "17 3 * * *"
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: live-validation
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
real-registry:
|
|
26
|
+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.run_real_registry }}
|
|
27
|
+
uses: ./.github/workflows/real-registry.yml
|
|
28
|
+
|
|
29
|
+
oci-pull-conformance:
|
|
30
|
+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.run_oci_pull_conformance }}
|
|
31
|
+
uses: ./.github/workflows/oci-conformance.yml
|
|
32
|
+
|
|
33
|
+
all-checks-passed:
|
|
34
|
+
name: Live validation passed
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
needs: [real-registry, oci-pull-conformance]
|
|
37
|
+
if: always()
|
|
38
|
+
steps:
|
|
39
|
+
- name: Verify scheduled validation jobs
|
|
40
|
+
run: |
|
|
41
|
+
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
42
|
+
echo "One or more live validation jobs failed or were cancelled"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
echo "Live validation jobs completed successfully"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
name: OCI Pull Conformance
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: oci-pull-conformance-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
pull:
|
|
16
|
+
name: Pull Conformance
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 20
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Install Rust
|
|
23
|
+
uses: dtolnay/rust-toolchain@stable
|
|
24
|
+
|
|
25
|
+
- name: Build Drayage
|
|
26
|
+
run: cargo build --locked
|
|
27
|
+
|
|
28
|
+
- name: Prepare conformance config
|
|
29
|
+
run: |
|
|
30
|
+
mkdir -p /tmp/drayage-conformance-cache
|
|
31
|
+
cat > /tmp/drayage-conformance.toml <<'EOF'
|
|
32
|
+
listen = "127.0.0.1:5001"
|
|
33
|
+
cache_dir = "/tmp/drayage-conformance-cache"
|
|
34
|
+
manifest_ttl_seconds = 900
|
|
35
|
+
negative_ttl_seconds = 60
|
|
36
|
+
connect_timeout_secs = 10
|
|
37
|
+
read_timeout_secs = 30
|
|
38
|
+
|
|
39
|
+
[upstreams.registry_k8s_io]
|
|
40
|
+
registry = "https://registry.k8s.io"
|
|
41
|
+
EOF
|
|
42
|
+
|
|
43
|
+
- name: Start Drayage
|
|
44
|
+
run: |
|
|
45
|
+
target/debug/drayage serve --config /tmp/drayage-conformance.toml --log-json \
|
|
46
|
+
> /tmp/drayage-conformance.log 2>&1 &
|
|
47
|
+
echo $! > /tmp/drayage-conformance.pid
|
|
48
|
+
|
|
49
|
+
- name: Wait for readiness
|
|
50
|
+
run: |
|
|
51
|
+
for _ in $(seq 1 60); do
|
|
52
|
+
if curl -fsS http://127.0.0.1:5001/readyz >/dev/null; then
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
sleep 1
|
|
56
|
+
done
|
|
57
|
+
cat /tmp/drayage-conformance.log
|
|
58
|
+
exit 1
|
|
59
|
+
|
|
60
|
+
- name: Resolve pull fixture
|
|
61
|
+
id: fixture
|
|
62
|
+
run: |
|
|
63
|
+
python3 scripts/resolve_oci_pull_fixture.py \
|
|
64
|
+
--root-url http://127.0.0.1:5001 \
|
|
65
|
+
--namespace registry.k8s.io/pause \
|
|
66
|
+
--reference 3.9 >> "$GITHUB_OUTPUT"
|
|
67
|
+
|
|
68
|
+
- name: Run official OCI Distribution pull conformance
|
|
69
|
+
uses: opencontainers/distribution-spec@v1.1.1
|
|
70
|
+
env:
|
|
71
|
+
OCI_ROOT_URL: http://127.0.0.1:5001
|
|
72
|
+
OCI_NAMESPACE: registry.k8s.io/pause
|
|
73
|
+
OCI_TAG_NAME: 3.9
|
|
74
|
+
OCI_MANIFEST_DIGEST: ${{ steps.fixture.outputs.manifest_digest }}
|
|
75
|
+
OCI_BLOB_DIGEST: ${{ steps.fixture.outputs.blob_digest }}
|
|
76
|
+
OCI_TEST_PULL: 1
|
|
77
|
+
OCI_HIDE_SKIPPED_WORKFLOWS: 1
|
|
78
|
+
OCI_DEBUG: 0
|
|
79
|
+
OCI_REPORT_DIR: ${{ github.workspace }}/oci-conformance-results
|
|
80
|
+
|
|
81
|
+
- name: Upload conformance artifacts
|
|
82
|
+
if: always()
|
|
83
|
+
uses: actions/upload-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: oci-pull-conformance-report
|
|
86
|
+
path: |
|
|
87
|
+
oci-conformance-results/junit.xml
|
|
88
|
+
oci-conformance-results/report.html
|
|
89
|
+
if-no-files-found: warn
|
|
90
|
+
retention-days: 14
|
|
91
|
+
|
|
92
|
+
- name: Print Drayage log
|
|
93
|
+
if: always()
|
|
94
|
+
run: cat /tmp/drayage-conformance.log
|
|
95
|
+
|
|
96
|
+
- name: Stop Drayage
|
|
97
|
+
if: always()
|
|
98
|
+
run: |
|
|
99
|
+
if [ -f /tmp/drayage-conformance.pid ]; then
|
|
100
|
+
kill "$(cat /tmp/drayage-conformance.pid)" || true
|
|
101
|
+
fi
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Real Registry Live Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: real-registry-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: true
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
real-registry:
|
|
16
|
+
name: Real Registry
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 20
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Install Rust
|
|
23
|
+
uses: dtolnay/rust-toolchain@stable
|
|
24
|
+
|
|
25
|
+
- name: Run live registry tests
|
|
26
|
+
run: |
|
|
27
|
+
mkdir -p live-test-artifacts
|
|
28
|
+
set -o pipefail
|
|
29
|
+
cargo test --locked --test real_registry -- --ignored --test-threads=1 \
|
|
30
|
+
2>&1 | tee live-test-artifacts/real-registry.log
|
|
31
|
+
|
|
32
|
+
- name: Upload live registry artifacts
|
|
33
|
+
if: always()
|
|
34
|
+
uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: real-registry-log
|
|
37
|
+
path: live-test-artifacts/real-registry.log
|
|
38
|
+
if-no-files-found: warn
|
|
39
|
+
retention-days: 14
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
dry_run:
|
|
10
|
+
description: "Dry run (skip publishing)"
|
|
11
|
+
type: boolean
|
|
12
|
+
default: true
|
|
13
|
+
skip_crates_io:
|
|
14
|
+
description: "Skip crates.io publish"
|
|
15
|
+
type: boolean
|
|
16
|
+
default: false
|
|
17
|
+
skip_pypi:
|
|
18
|
+
description: "Skip PyPI publish"
|
|
19
|
+
type: boolean
|
|
20
|
+
default: false
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: write
|
|
24
|
+
packages: write
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: release
|
|
28
|
+
cancel-in-progress: false
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
test:
|
|
32
|
+
name: Test
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- name: Install Rust
|
|
38
|
+
uses: dtolnay/rust-toolchain@stable
|
|
39
|
+
|
|
40
|
+
- name: Run tests
|
|
41
|
+
run: make test
|
|
42
|
+
|
|
43
|
+
real-registry:
|
|
44
|
+
name: Real Registry
|
|
45
|
+
uses: ./.github/workflows/real-registry.yml
|
|
46
|
+
|
|
47
|
+
oci-pull-conformance:
|
|
48
|
+
name: OCI Pull Conformance
|
|
49
|
+
uses: ./.github/workflows/oci-conformance.yml
|
|
50
|
+
|
|
51
|
+
build-wheels:
|
|
52
|
+
name: Build wheel (${{ matrix.target }})
|
|
53
|
+
needs: [test, real-registry, oci-pull-conformance]
|
|
54
|
+
runs-on: ${{ matrix.os }}
|
|
55
|
+
strategy:
|
|
56
|
+
matrix:
|
|
57
|
+
include:
|
|
58
|
+
- target: x86_64-unknown-linux-gnu
|
|
59
|
+
os: ubuntu-latest
|
|
60
|
+
manylinux: manylinux_2_28
|
|
61
|
+
- target: aarch64-unknown-linux-gnu
|
|
62
|
+
os: ubuntu-latest
|
|
63
|
+
manylinux: manylinux_2_28
|
|
64
|
+
- target: x86_64-apple-darwin
|
|
65
|
+
os: macos-14
|
|
66
|
+
- target: aarch64-apple-darwin
|
|
67
|
+
os: macos-14
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v4
|
|
70
|
+
|
|
71
|
+
- name: Build wheel
|
|
72
|
+
uses: PyO3/maturin-action@v1
|
|
73
|
+
id: build
|
|
74
|
+
continue-on-error: true
|
|
75
|
+
with:
|
|
76
|
+
target: ${{ matrix.target }}
|
|
77
|
+
args: --release --strip --out dist
|
|
78
|
+
manylinux: ${{ matrix.manylinux || 'auto' }}
|
|
79
|
+
|
|
80
|
+
- name: Retry build wheel
|
|
81
|
+
if: steps.build.outcome == 'failure'
|
|
82
|
+
uses: PyO3/maturin-action@v1
|
|
83
|
+
with:
|
|
84
|
+
target: ${{ matrix.target }}
|
|
85
|
+
args: --release --strip --out dist
|
|
86
|
+
manylinux: ${{ matrix.manylinux || 'auto' }}
|
|
87
|
+
env:
|
|
88
|
+
CARGO_INCREMENTAL: "0"
|
|
89
|
+
|
|
90
|
+
- name: Upload wheel
|
|
91
|
+
uses: actions/upload-artifact@v4
|
|
92
|
+
with:
|
|
93
|
+
name: wheel-${{ matrix.target }}
|
|
94
|
+
path: dist/*.whl
|
|
95
|
+
|
|
96
|
+
sdist:
|
|
97
|
+
name: Build source distribution
|
|
98
|
+
needs: [test, real-registry, oci-pull-conformance]
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
|
|
103
|
+
- name: Build sdist
|
|
104
|
+
uses: PyO3/maturin-action@v1
|
|
105
|
+
with:
|
|
106
|
+
command: sdist
|
|
107
|
+
args: --out dist
|
|
108
|
+
|
|
109
|
+
- name: Upload sdist
|
|
110
|
+
uses: actions/upload-artifact@v4
|
|
111
|
+
with:
|
|
112
|
+
name: sdist
|
|
113
|
+
path: dist/*.tar.gz
|
|
114
|
+
|
|
115
|
+
container:
|
|
116
|
+
name: Build container image
|
|
117
|
+
needs: [test, real-registry, oci-pull-conformance]
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
|
|
122
|
+
- name: Set up QEMU
|
|
123
|
+
uses: docker/setup-qemu-action@v3
|
|
124
|
+
|
|
125
|
+
- name: Set up Docker Buildx
|
|
126
|
+
uses: docker/setup-buildx-action@v3
|
|
127
|
+
|
|
128
|
+
- name: Login to GHCR
|
|
129
|
+
if: ${{ inputs.dry_run != true && startsWith(github.ref, 'refs/tags/v') }}
|
|
130
|
+
uses: docker/login-action@v3
|
|
131
|
+
with:
|
|
132
|
+
registry: ghcr.io
|
|
133
|
+
username: ${{ github.actor }}
|
|
134
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
135
|
+
|
|
136
|
+
- name: Docker metadata
|
|
137
|
+
id: meta
|
|
138
|
+
uses: docker/metadata-action@v5
|
|
139
|
+
with:
|
|
140
|
+
images: ghcr.io/${{ github.repository }}
|
|
141
|
+
tags: |
|
|
142
|
+
type=ref,event=tag
|
|
143
|
+
type=semver,pattern={{version}}
|
|
144
|
+
type=raw,value=dry-run,enable=${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
145
|
+
|
|
146
|
+
- name: Build and optionally push image
|
|
147
|
+
uses: docker/build-push-action@v6
|
|
148
|
+
with:
|
|
149
|
+
context: .
|
|
150
|
+
platforms: linux/amd64,linux/arm64
|
|
151
|
+
push: ${{ inputs.dry_run != true && startsWith(github.ref, 'refs/tags/v') }}
|
|
152
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
153
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
154
|
+
|
|
155
|
+
release:
|
|
156
|
+
name: Publish
|
|
157
|
+
needs: [build-wheels, sdist, container]
|
|
158
|
+
runs-on: ubuntu-latest
|
|
159
|
+
steps:
|
|
160
|
+
- uses: actions/checkout@v4
|
|
161
|
+
|
|
162
|
+
- name: Install Rust
|
|
163
|
+
uses: dtolnay/rust-toolchain@stable
|
|
164
|
+
|
|
165
|
+
- name: Download wheel artifacts
|
|
166
|
+
uses: actions/download-artifact@v4
|
|
167
|
+
with:
|
|
168
|
+
pattern: wheel-*
|
|
169
|
+
path: ${{ runner.temp }}/artifacts
|
|
170
|
+
|
|
171
|
+
- name: Download sdist artifact
|
|
172
|
+
uses: actions/download-artifact@v4
|
|
173
|
+
with:
|
|
174
|
+
pattern: sdist
|
|
175
|
+
path: ${{ runner.temp }}/artifacts
|
|
176
|
+
|
|
177
|
+
- name: Publish to crates.io
|
|
178
|
+
if: ${{ inputs.dry_run != true && inputs.skip_crates_io != true }}
|
|
179
|
+
env:
|
|
180
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
181
|
+
run: cargo publish --locked
|
|
182
|
+
|
|
183
|
+
- name: Collect PyPI artifacts
|
|
184
|
+
if: ${{ inputs.dry_run != true && inputs.skip_pypi != true }}
|
|
185
|
+
run: |
|
|
186
|
+
mkdir -p ${{ runner.temp }}/pypi-dist
|
|
187
|
+
cp ${{ runner.temp }}/artifacts/wheel-*/*.whl ${{ runner.temp }}/pypi-dist/
|
|
188
|
+
cp ${{ runner.temp }}/artifacts/sdist/*.tar.gz ${{ runner.temp }}/pypi-dist/
|
|
189
|
+
|
|
190
|
+
- name: Publish to PyPI
|
|
191
|
+
if: ${{ inputs.dry_run != true && inputs.skip_pypi != true }}
|
|
192
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
193
|
+
with:
|
|
194
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
195
|
+
packages-dir: ${{ runner.temp }}/pypi-dist/
|
|
196
|
+
|
|
197
|
+
- name: Create GitHub Release
|
|
198
|
+
if: ${{ inputs.dry_run != true && startsWith(github.ref, 'refs/tags/v') }}
|
|
199
|
+
uses: softprops/action-gh-release@v2
|
|
200
|
+
with:
|
|
201
|
+
generate_release_notes: true
|
|
202
|
+
files: |
|
|
203
|
+
${{ runner.temp }}/artifacts/wheel-*/*.whl
|
|
204
|
+
${{ runner.temp }}/artifacts/sdist/*.tar.gz
|
|
205
|
+
|
|
206
|
+
- name: Dry run summary
|
|
207
|
+
if: ${{ inputs.dry_run == true }}
|
|
208
|
+
run: |
|
|
209
|
+
echo "Dry run - would have published:"
|
|
210
|
+
find "$RUNNER_TEMP/artifacts" -type f | sort
|
|
211
|
+
|
|
212
|
+
verify:
|
|
213
|
+
name: Verify
|
|
214
|
+
needs: [release]
|
|
215
|
+
if: ${{ inputs.dry_run != true && startsWith(github.ref, 'refs/tags/v') }}
|
|
216
|
+
runs-on: ubuntu-latest
|
|
217
|
+
steps:
|
|
218
|
+
- name: Verify crates.io
|
|
219
|
+
if: ${{ inputs.skip_crates_io != true }}
|
|
220
|
+
run: |
|
|
221
|
+
version="${GITHUB_REF_NAME#v}"
|
|
222
|
+
for attempt in 1 2 3 4 5; do
|
|
223
|
+
status=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
224
|
+
-H "User-Agent: drayage-release-verify" \
|
|
225
|
+
"https://crates.io/api/v1/crates/drayage/${version}")
|
|
226
|
+
if [ "$status" = "200" ]; then
|
|
227
|
+
echo "drayage ${version} verified on crates.io (attempt ${attempt})"
|
|
228
|
+
exit 0
|
|
229
|
+
fi
|
|
230
|
+
echo "Attempt ${attempt}: crates.io returned HTTP ${status}, retrying in 15s..."
|
|
231
|
+
sleep 15
|
|
232
|
+
done
|
|
233
|
+
echo "::error::drayage ${version} not found on crates.io after 5 attempts"
|
|
234
|
+
exit 1
|
|
235
|
+
|
|
236
|
+
- name: Verify PyPI
|
|
237
|
+
if: ${{ inputs.skip_pypi != true }}
|
|
238
|
+
run: |
|
|
239
|
+
version="${GITHUB_REF_NAME#v}"
|
|
240
|
+
for attempt in 1 2 3 4 5; do
|
|
241
|
+
status=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
242
|
+
"https://pypi.org/pypi/drayage/${version}/json")
|
|
243
|
+
if [ "$status" = "200" ]; then
|
|
244
|
+
echo "drayage ${version} verified on PyPI (attempt ${attempt})"
|
|
245
|
+
exit 0
|
|
246
|
+
fi
|
|
247
|
+
echo "Attempt ${attempt}: PyPI returned HTTP ${status}, retrying in 15s..."
|
|
248
|
+
sleep 15
|
|
249
|
+
done
|
|
250
|
+
echo "::error::drayage ${version} not found on PyPI after 5 attempts"
|
|
251
|
+
exit 1
|
|
252
|
+
|
|
253
|
+
- name: Verify GHCR
|
|
254
|
+
run: |
|
|
255
|
+
version="${GITHUB_REF_NAME#v}"
|
|
256
|
+
for attempt in 1 2 3 4 5; do
|
|
257
|
+
token=$(curl -s "https://ghcr.io/token?scope=repository:rvben/drayage:pull" | jq -r .token)
|
|
258
|
+
status=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
259
|
+
-H "Authorization: Bearer ${token}" \
|
|
260
|
+
-H "Accept: application/vnd.oci.image.index.v1+json" \
|
|
261
|
+
"https://ghcr.io/v2/rvben/drayage/manifests/${version}")
|
|
262
|
+
if [ "$status" = "200" ]; then
|
|
263
|
+
echo "drayage ${version} verified on GHCR (attempt ${attempt})"
|
|
264
|
+
exit 0
|
|
265
|
+
fi
|
|
266
|
+
echo "Attempt ${attempt}: GHCR returned HTTP ${status}, retrying in 15s..."
|
|
267
|
+
sleep 15
|
|
268
|
+
done
|
|
269
|
+
echo "::error::drayage ${version} not found on GHCR after 5 attempts"
|
|
270
|
+
exit 1
|
drayage-0.2.6/.gitignore
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
fail_fast: true
|
|
2
|
+
|
|
3
|
+
repos:
|
|
4
|
+
# Secret detection
|
|
5
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
6
|
+
rev: v8.30.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: gitleaks
|
|
9
|
+
|
|
10
|
+
# Conventional Commits validation
|
|
11
|
+
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
12
|
+
rev: v3.6.0
|
|
13
|
+
hooks:
|
|
14
|
+
- id: conventional-pre-commit
|
|
15
|
+
stages: [commit-msg]
|
|
16
|
+
|
|
17
|
+
# Rust formatting and linting
|
|
18
|
+
- repo: local
|
|
19
|
+
hooks:
|
|
20
|
+
- id: cargo-fmt
|
|
21
|
+
name: cargo fmt
|
|
22
|
+
entry: cargo fmt --all --
|
|
23
|
+
language: system
|
|
24
|
+
types: [rust]
|
|
25
|
+
pass_filenames: false
|
|
26
|
+
|
|
27
|
+
- id: cargo-clippy
|
|
28
|
+
name: cargo clippy
|
|
29
|
+
entry: cargo clippy -- -D warnings
|
|
30
|
+
language: system
|
|
31
|
+
types: [rust]
|
|
32
|
+
pass_filenames: false
|
|
33
|
+
|
|
34
|
+
- id: cargo-lock-check
|
|
35
|
+
name: check Cargo.lock is up-to-date
|
|
36
|
+
entry: sh -c 'cargo metadata --locked --format-version 1 --no-deps >/dev/null'
|
|
37
|
+
language: system
|
|
38
|
+
files: ^Cargo\.(toml|lock)$
|
|
39
|
+
pass_filenames: false
|
|
40
|
+
|
|
41
|
+
# General file quality checks
|
|
42
|
+
- repo: builtin
|
|
43
|
+
hooks:
|
|
44
|
+
- id: trailing-whitespace
|
|
45
|
+
- id: end-of-file-fixer
|
|
46
|
+
- id: check-yaml
|
|
47
|
+
- id: check-toml
|
|
48
|
+
- id: check-merge-conflict
|
|
49
|
+
- id: check-case-conflict
|
|
50
|
+
- id: mixed-line-ending
|
|
51
|
+
args: [--fix=lf]
|
|
52
|
+
|
|
53
|
+
# Pre-push hooks
|
|
54
|
+
- repo: local
|
|
55
|
+
hooks:
|
|
56
|
+
- id: cargo-test
|
|
57
|
+
name: cargo test
|
|
58
|
+
entry: make test
|
|
59
|
+
language: system
|
|
60
|
+
types: [rust]
|
|
61
|
+
pass_filenames: false
|
|
62
|
+
stages: [pre-push]
|
|
63
|
+
|
|
64
|
+
- id: cargo-lint
|
|
65
|
+
name: cargo clippy (all targets)
|
|
66
|
+
entry: make lint
|
|
67
|
+
language: system
|
|
68
|
+
types: [rust]
|
|
69
|
+
pass_filenames: false
|
|
70
|
+
stages: [pre-push]
|
|
71
|
+
|
|
72
|
+
- id: cargo-lock-check-push
|
|
73
|
+
name: verify Cargo.lock is committed and up-to-date
|
|
74
|
+
entry: sh -c 'cargo metadata --locked --format-version 1 --no-deps >/dev/null'
|
|
75
|
+
language: system
|
|
76
|
+
files: ^Cargo\.(toml|lock)$
|
|
77
|
+
pass_filenames: false
|
|
78
|
+
stages: [pre-push]
|