mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 08:32:16 +01:00
Compare commits
433 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb472124c4 | ||
|
|
f584fa2dc0 | ||
|
|
81d43cfbad | ||
|
|
fe72902cdb | ||
|
|
8898bd2b4a | ||
|
|
a62abef215 | ||
|
|
cf9fd7eedc | ||
|
|
7af3cd1ff5 | ||
|
|
4296474889 | ||
|
|
bfde451e4e | ||
|
|
fd8c5441d8 | ||
|
|
d7421748d0 | ||
|
|
0e13cc3ed8 | ||
|
|
cb49e8e4d1 | ||
|
|
3113e034f6 | ||
|
|
85291fdec3 | ||
|
|
57e1b7efda | ||
|
|
be78a71bb7 | ||
|
|
2baa59cb3a | ||
|
|
aea7c5952a | ||
|
|
cbde321d3b | ||
|
|
aa5de988cf | ||
|
|
fd485a0d3e | ||
|
|
aea06a98b7 | ||
|
|
82401bdfdd | ||
|
|
12c25a2d21 | ||
|
|
241d5077c9 | ||
|
|
37757315d0 | ||
|
|
1195c37508 | ||
|
|
3d9b2deb59 | ||
|
|
32d948554f | ||
|
|
b7a6b7aba2 | ||
|
|
05e15a1d06 | ||
|
|
f57ecb6ef2 | ||
|
|
45318497d2 | ||
|
|
b762143d75 | ||
|
|
ba1a730d3a | ||
|
|
463bb2f91c | ||
|
|
e14cab0c8b | ||
|
|
3220ca4140 | ||
|
|
92de0cf6fe | ||
|
|
d111591c8b | ||
|
|
935686b9e3 | ||
|
|
b1ad21c7d3 | ||
|
|
4f800c8a76 | ||
|
|
5c498219ed | ||
|
|
0b211c39eb | ||
|
|
77b9776d9c | ||
|
|
04e596b616 | ||
|
|
9fba76fe5c | ||
|
|
8b9858aa66 | ||
|
|
2f7218b09c | ||
|
|
0a05091241 | ||
|
|
507d0cb2e2 | ||
|
|
fb61948244 | ||
|
|
15fdc99ec0 | ||
|
|
dd07c73c28 | ||
|
|
43354cafb1 | ||
|
|
b2c3187690 | ||
|
|
4a788ce9d8 | ||
|
|
f9ad8bd2d5 | ||
|
|
4429aea8a4 | ||
|
|
7a60e82d03 | ||
|
|
3544e9c355 | ||
|
|
ca4f0141c6 | ||
|
|
fcaa26a84d | ||
|
|
ea103d3070 | ||
|
|
286efbe548 | ||
|
|
a0ee800002 | ||
|
|
f4d3fba306 | ||
|
|
d5a58cfcb5 | ||
|
|
0e6bb27ecf | ||
|
|
83fdc01df1 | ||
|
|
c7ccabc6cb | ||
|
|
3eefe33e64 | ||
|
|
c44dc7f0ab | ||
|
|
1639d82348 | ||
|
|
b31e520731 | ||
|
|
e85d4143c0 | ||
|
|
da20f04e25 | ||
|
|
9a49ea426e | ||
|
|
c0c4c21682 | ||
|
|
c7424dfcb3 | ||
|
|
e33ca6af12 | ||
|
|
9dc6e308b6 | ||
|
|
4fe2ff5553 | ||
|
|
e5ccb82db8 | ||
|
|
63ae987010 | ||
|
|
efa0d3fd75 | ||
|
|
fd5930bc56 | ||
|
|
a057c6253b | ||
|
|
ed5d1fa891 | ||
|
|
76d36d18be | ||
|
|
a78c433a60 | ||
|
|
aff7530cb0 | ||
|
|
e7e7267fc2 | ||
|
|
9aaab2de3b | ||
|
|
8f0121a92d | ||
|
|
beb1e386c2 | ||
|
|
5b84a5e0e9 | ||
|
|
a9613651a5 | ||
|
|
d6ebc7f230 | ||
|
|
84ca118524 | ||
|
|
0ad6623e24 | ||
|
|
ba944f9dc2 | ||
|
|
99307befdd | ||
|
|
638c4e6b23 | ||
|
|
18bb7ef00d | ||
|
|
3dd9ce1fcd | ||
|
|
fd4814194c | ||
|
|
4d526fe419 | ||
|
|
50d1b187bb | ||
|
|
f54f78d186 | ||
|
|
97ec4949d7 | ||
|
|
f08b9d389b | ||
|
|
4fc94cae24 | ||
|
|
8cab8230e6 | ||
|
|
b7afa49c9f | ||
|
|
e0b5ccb41d | ||
|
|
fb63ffb919 | ||
|
|
cb98b0c937 | ||
|
|
bee56cfd99 | ||
|
|
9e130614ce | ||
|
|
2f487d2e83 | ||
|
|
1ff4b3a4fc | ||
|
|
e86d38c52c | ||
|
|
d371ae8ceb | ||
|
|
a9d10b2bf3 | ||
|
|
d6ffd193d3 | ||
|
|
2635213947 | ||
|
|
d496cbfb53 | ||
|
|
db8f0ad9ee | ||
|
|
8d795a4317 | ||
|
|
1a9ae456dd | ||
|
|
4e9d7a3f8c | ||
|
|
087967befb | ||
|
|
02ad6c7834 | ||
|
|
fc11f557fa | ||
|
|
f299f3ed20 | ||
|
|
94c831cd05 | ||
|
|
53b4c70e4b | ||
|
|
6ff5109b00 | ||
|
|
339afe614c | ||
|
|
911fdd3067 | ||
|
|
588e27e6d1 | ||
|
|
3a71032d62 | ||
|
|
59a091e7dc | ||
|
|
0e250a99ed | ||
|
|
f73b72753f | ||
|
|
00a85b0d90 | ||
|
|
e79d7e6fb5 | ||
|
|
ef745dc378 | ||
|
|
ac5dfb7ff0 | ||
|
|
51b0841171 | ||
|
|
57264da21b | ||
|
|
16f740b318 | ||
|
|
2ba70141cc | ||
|
|
e945329d91 | ||
|
|
ffeb4703fd | ||
|
|
fcf41187fa | ||
|
|
f0fc704efc | ||
|
|
aa58615650 | ||
|
|
b0a84bcbf7 | ||
|
|
cf2d413a28 | ||
|
|
9226b78b0c | ||
|
|
a635fd8a7b | ||
|
|
6f714277f7 | ||
|
|
4aff4982b0 | ||
|
|
8634989497 | ||
|
|
a50e60b2a0 | ||
|
|
8875f4dfc4 | ||
|
|
61c8217ed5 | ||
|
|
f75912033e | ||
|
|
1d8630810b | ||
|
|
ce155fb43e | ||
|
|
67ebe17fcb | ||
|
|
f13a6c0a3b | ||
|
|
e1870429b9 | ||
|
|
5aa1cd7f40 | ||
|
|
de1b887d29 | ||
|
|
e662f5ce0b | ||
|
|
790b69a32e | ||
|
|
9aaab97d6a | ||
|
|
66317197b6 | ||
|
|
91757335ac | ||
|
|
be3145aae9 | ||
|
|
79425af848 | ||
|
|
45b47a1071 | ||
|
|
4b30567c39 | ||
|
|
1ed33a7400 | ||
|
|
ca1d11006c | ||
|
|
71f1f3dd22 | ||
|
|
64add9a542 | ||
|
|
a7c02438e4 | ||
|
|
910af7a44c | ||
|
|
05f9ac3745 | ||
|
|
5c43eefe46 | ||
|
|
b63f4c53d2 | ||
|
|
3d652bc829 | ||
|
|
c78ef8771d | ||
|
|
9a38f16219 | ||
|
|
e5363205a7 | ||
|
|
088b3274f2 | ||
|
|
fabe323e34 | ||
|
|
a731bf034e | ||
|
|
3cbf772acf | ||
|
|
9701f88ae3 | ||
|
|
7ca1d118a1 | ||
|
|
a7dfa21cbf | ||
|
|
ab81444773 | ||
|
|
02c4343dfd | ||
|
|
1bfe86738f | ||
|
|
7fe0e05050 | ||
|
|
10588efe25 | ||
|
|
bf4607d368 | ||
|
|
45f04ae8d4 | ||
|
|
674f1de183 | ||
|
|
368c4fa1a7 | ||
|
|
c737579b7f | ||
|
|
0b7c51a323 | ||
|
|
e7c77b7bf3 | ||
|
|
6c727b7e51 | ||
|
|
a9754d6a1c | ||
|
|
218052d5dd | ||
|
|
f112cb748f | ||
|
|
67a65c66b6 | ||
|
|
cd6add14a0 | ||
|
|
33f9f1ddf4 | ||
|
|
2131de77b0 | ||
|
|
0febb60a3f | ||
|
|
820b914291 | ||
|
|
536d3ee70d | ||
|
|
2544d82486 | ||
|
|
ea6854fadc | ||
|
|
147e3b1173 | ||
|
|
8252142e65 | ||
|
|
6e2270632e | ||
|
|
7d14546d3b | ||
|
|
b31024c362 | ||
|
|
85eaef05ad | ||
|
|
16e4c10862 | ||
|
|
904e0f61a8 | ||
|
|
70953aa66e | ||
|
|
d41de5d270 | ||
|
|
d8603f4f34 | ||
|
|
b13a8094ea | ||
|
|
28e07bad54 | ||
|
|
81cc483166 | ||
|
|
8d7cc55c28 | ||
|
|
083e0e307a | ||
|
|
80f3f89a89 | ||
|
|
3dc8c18849 | ||
|
|
0a6a97cf07 | ||
|
|
7676d7a239 | ||
|
|
679715f896 | ||
|
|
d5aa880336 | ||
|
|
08daa86766 | ||
|
|
f0c1952dfe | ||
|
|
198d9115cc | ||
|
|
6b0c01bd3e | ||
|
|
a1848d3c75 | ||
|
|
a1596f7c62 | ||
|
|
740e701ad3 | ||
|
|
71d571a25c | ||
|
|
2293300182 | ||
|
|
85c7f2806f | ||
|
|
27ecb4fe49 | ||
|
|
7afeefe84f | ||
|
|
651922194f | ||
|
|
1d1b4fb04d | ||
|
|
b418f1eb05 | ||
|
|
a9b44ee39e | ||
|
|
cb48355898 | ||
|
|
6ce47e3a20 | ||
|
|
09e511bc49 | ||
|
|
66ade27383 | ||
|
|
d96058d589 | ||
|
|
8631a15933 | ||
|
|
c0bf81ad7c | ||
|
|
8fd1fa203e | ||
|
|
51b907bcf5 | ||
|
|
ecb5d974c5 | ||
|
|
19c91aff19 | ||
|
|
8e0cc7dd2f | ||
|
|
6478528ebc | ||
|
|
3e3b24f611 | ||
|
|
6dc7d70a1f | ||
|
|
a6f4c5651c | ||
|
|
291a4d39fe | ||
|
|
e639a1dd73 | ||
|
|
e3a961623b | ||
|
|
1ca27fdba2 | ||
|
|
f72428056a | ||
|
|
bdb3f11ac7 | ||
|
|
2f69af1a52 | ||
|
|
984cf77ee0 | ||
|
|
1762596fce | ||
|
|
910eb9b770 | ||
|
|
16807bd57f | ||
|
|
8bc29ad92d | ||
|
|
51a913a5e4 | ||
|
|
c30da805b3 | ||
|
|
42ee593708 | ||
|
|
1b49b35365 | ||
|
|
333ab7066c | ||
|
|
66dbdc09b5 | ||
|
|
79f396f6ff | ||
|
|
62ba4877ac | ||
|
|
e65a5e6d22 | ||
|
|
711b43070d | ||
|
|
b2f957d1d8 | ||
|
|
249745f256 | ||
|
|
8ff9d3bcf1 | ||
|
|
99c328c302 | ||
|
|
8a9f0a245e | ||
|
|
9daecc127a | ||
|
|
119bba4f04 | ||
|
|
bf205c579d | ||
|
|
aa57b17254 | ||
|
|
7df786c5c6 | ||
|
|
b315464e98 | ||
|
|
1252ea076b | ||
|
|
d970e446a8 | ||
|
|
fe40f3727b | ||
|
|
10a290b065 | ||
|
|
0abb11b42a | ||
|
|
1eb6eb729a | ||
|
|
e371a4a3c3 | ||
|
|
f2b6bd3d4b | ||
|
|
d21f87b543 | ||
|
|
b8cdee4f45 | ||
|
|
b06d7445d9 | ||
|
|
2aa9cceb32 | ||
|
|
ae2a2a8a07 | ||
|
|
286555411b | ||
|
|
3c42aec180 | ||
|
|
a203ae00c6 | ||
|
|
68784616a4 | ||
|
|
5cd8c6a5da | ||
|
|
a3647fea8a | ||
|
|
300e73f07d | ||
|
|
03ced23f05 | ||
|
|
da8eeb5d8f | ||
|
|
16cf02896f | ||
|
|
c9f10d248e | ||
|
|
3297e41289 | ||
|
|
4e1b347797 | ||
|
|
4602332dbb | ||
|
|
e1f69ee533 | ||
|
|
d90e431b5b | ||
|
|
45a9eca0ce | ||
|
|
af202f4871 | ||
|
|
7b32fa35f3 | ||
|
|
0c40b230dc | ||
|
|
2baba67bfc | ||
|
|
b1e69a9059 | ||
|
|
f87362ec1b | ||
|
|
84dc57373a | ||
|
|
b3f4a02658 | ||
|
|
50304dbefe | ||
|
|
bf01af0bf3 | ||
|
|
0e3fe3463b | ||
|
|
3956763825 | ||
|
|
d6fe895f6e | ||
|
|
697fa08d8b | ||
|
|
669a35afef | ||
|
|
b1d94a3845 | ||
|
|
06869cf491 | ||
|
|
ed67d8514c | ||
|
|
07ec2f3d7b | ||
|
|
73d02e85c4 | ||
|
|
c1cf1eb37a | ||
|
|
7aecc94049 | ||
|
|
b55fbfeb8e | ||
|
|
20b8991fa4 | ||
|
|
e50de4201d | ||
|
|
ba2b876ee4 | ||
|
|
9b1399c9d5 | ||
|
|
020a2f00c2 | ||
|
|
8713946f35 | ||
|
|
bed8c25e40 | ||
|
|
7c51a09068 | ||
|
|
0f0a6ce042 | ||
|
|
a890968ee4 | ||
|
|
2267c5be00 | ||
|
|
e853cfb98a | ||
|
|
f89a0db471 | ||
|
|
1d66b43da1 | ||
|
|
75c4a4f253 | ||
|
|
6a9c95b3b1 | ||
|
|
c11a2d0081 | ||
|
|
43a13ff2c5 | ||
|
|
8454d163eb | ||
|
|
4a11f6a39f | ||
|
|
c63235cd3d | ||
|
|
f4ce196a34 | ||
|
|
e644b27201 | ||
|
|
d2b14582ee | ||
|
|
ca9194fd96 | ||
|
|
773d3ab13c | ||
|
|
a02a4a07a5 | ||
|
|
0a8625227f | ||
|
|
dc613aa2bf | ||
|
|
2008ac5663 | ||
|
|
da326f1925 | ||
|
|
71911cb1a7 | ||
|
|
31e7582216 | ||
|
|
91f63047e0 | ||
|
|
c9aa4938f4 | ||
|
|
b9e6a38037 | ||
|
|
eb054146d2 | ||
|
|
a780373cfc | ||
|
|
5ad90ccdb8 | ||
|
|
ef97d81ca8 | ||
|
|
c9f7b642c5 | ||
|
|
770962be3f | ||
|
|
d6c857f4a8 | ||
|
|
7b7ffb427d | ||
|
|
b80318d1b6 | ||
|
|
3997d69e49 | ||
|
|
4af41b33c0 | ||
|
|
0f8bbead66 | ||
|
|
804fcff5b6 | ||
|
|
d18e6920fc | ||
|
|
c95174ff11 | ||
|
|
c70329c22b | ||
|
|
34f69263a2 | ||
|
|
bf5056f8fe | ||
|
|
c47f5b06ba | ||
|
|
63055e3df2 | ||
|
|
8ee555140b | ||
|
|
859f78e986 | ||
|
|
366eebb68c |
@@ -1 +1 @@
|
|||||||
.git
|
.git
|
||||||
|
|||||||
7
.env
Normal file
7
.env
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
GOTENBERG_VERSION=snapshot
|
||||||
|
DOCKER_REGISTRY=gotenberg
|
||||||
|
DOCKER_REPOSITORY=gotenberg
|
||||||
|
DOCKERFILE=build/Dockerfile
|
||||||
|
DOCKERFILE_CLOUDRUN=build/Dockerfile.cloudrun
|
||||||
|
DOCKERFILE_AWS_LAMBDA=build/Dockerfile.aws-lambda
|
||||||
|
DOCKER_BUILD_CONTEXT='.'
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
github: [gulien]
|
||||||
93
.github/actions/build-test-push/action.yml
vendored
Normal file
93
.github/actions/build-test-push/action.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
name: Build Test Push
|
||||||
|
description: Build, test and push Docker images for a given platform
|
||||||
|
author: Julien Neuhart
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
github_token:
|
||||||
|
description: The GitHub token
|
||||||
|
required: true
|
||||||
|
default: ${{ github.token }}
|
||||||
|
docker_hub_username:
|
||||||
|
description: The Docker Hub username
|
||||||
|
required: true
|
||||||
|
docker_hub_password:
|
||||||
|
description: The Docker Hub password
|
||||||
|
required: true
|
||||||
|
platform:
|
||||||
|
description: linux/amd64, linux/ppc64le, linux/386, linux/arm64, linux/arm/v7
|
||||||
|
required: true
|
||||||
|
version:
|
||||||
|
description: Gotenberg version
|
||||||
|
required: true
|
||||||
|
skip_integrations_tests:
|
||||||
|
description: Define whether to skip integration testing
|
||||||
|
default: false
|
||||||
|
alternate_repository:
|
||||||
|
description: Alternate repository to push the tags to
|
||||||
|
dry_run:
|
||||||
|
description: Dry run this action
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
tags:
|
||||||
|
description: Comma separated list of tag
|
||||||
|
value: ${{ steps.build.outputs.tags }}
|
||||||
|
tags_cloud_run:
|
||||||
|
description: Comma separated list of Cloud Run tags (linux/amd64 only)
|
||||||
|
value: ${{ steps.build.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda:
|
||||||
|
description: Comma separated list of AWS Lambda tags (linux/amd64 and linux/arm64 only)
|
||||||
|
value: ${{ steps.build.outputs.tags_aws_lambda }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
if: inputs.docker_hub_username != ''
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ inputs.docker_hub_username }}
|
||||||
|
password: ${{ inputs.docker_hub_password }}
|
||||||
|
|
||||||
|
- name: Build ${{ inputs.platform }}
|
||||||
|
id: build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
.github/actions/build-test-push/build.sh \
|
||||||
|
--version "${{ inputs.version }}" \
|
||||||
|
--platform "${{ inputs.platform }}" \
|
||||||
|
--alternate-repository "${{ inputs.alternate_repository }}" \
|
||||||
|
--dry-run "${{ inputs.dry_run }}"
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
if: inputs.skip_integrations_tests != 'true'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
.github/actions/build-test-push/test.sh \
|
||||||
|
--version "${{ inputs.version }}" \
|
||||||
|
--platform "${{ inputs.platform }}" \
|
||||||
|
--alternate-repository "${{ inputs.alternate_repository }}" \
|
||||||
|
--dry-run "${{ inputs.dry_run }}"
|
||||||
|
|
||||||
|
- name: Push
|
||||||
|
if: inputs.docker_hub_username != ''
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
.github/actions/build-test-push/push.sh \
|
||||||
|
--tags "${{ steps.build.outputs.tags }},${{ steps.build.outputs.tags_cloud_run }},${{ steps.build.outputs.tags_aws_lambda }}" \
|
||||||
|
--dry-run "${{ inputs.dry_run }}"
|
||||||
|
|
||||||
|
- name: Outputs
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "tags=${{ steps.build.outputs.tags }}"
|
||||||
|
echo "tags_cloud_run=${{ steps.build.outputs.tags_cloud_run }}"
|
||||||
|
echo "tags_aws_lambda=${{ steps.build.outputs.tags_aws_lambda }}"
|
||||||
184
.github/actions/build-test-push/build.sh
vendored
Executable file
184
.github/actions/build-test-push/build.sh
vendored
Executable file
@@ -0,0 +1,184 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit early.
|
||||||
|
# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source dot env file.
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
version=""
|
||||||
|
platform=""
|
||||||
|
alternate_repository=""
|
||||||
|
dry_run=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--version)
|
||||||
|
version="${2//v/}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--platform)
|
||||||
|
platform="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--alternate-repository)
|
||||||
|
alternate_repository="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
dry_run="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Build and push 👷"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "Gotenberg version: $version"
|
||||||
|
echo "Target platform: $platform"
|
||||||
|
|
||||||
|
if [ -n "$alternate_repository" ]; then
|
||||||
|
DOCKER_REPOSITORY=$alternate_repository
|
||||||
|
echo "⚠️ Using $alternate_repository for DOCKER_REPOSITORY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build tags arrays.
|
||||||
|
tags=()
|
||||||
|
tags_cloud_run=()
|
||||||
|
tags_aws_lambda=()
|
||||||
|
|
||||||
|
IFS='/' read -ra arch <<< "$platform"
|
||||||
|
IFS='.' read -ra semver <<< "$version"
|
||||||
|
|
||||||
|
if [ "${#semver[@]}" -eq 3 ]; then
|
||||||
|
echo
|
||||||
|
echo "Semver version detected"
|
||||||
|
|
||||||
|
major="${semver[0]}"
|
||||||
|
minor="${semver[1]}"
|
||||||
|
patch="${semver[2]}"
|
||||||
|
|
||||||
|
tags+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:latest-${arch[1]}")
|
||||||
|
tags+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major-${arch[1]}")
|
||||||
|
tags+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-${arch[1]}")
|
||||||
|
tags+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-${arch[1]}")
|
||||||
|
|
||||||
|
if [ "$platform" = "linux/amd64" ]; then
|
||||||
|
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:latest-cloudrun")
|
||||||
|
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major-cloudrun")
|
||||||
|
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-cloudrun")
|
||||||
|
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-cloudrun")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
|
||||||
|
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:latest-aws-lambda-${arch[1]}")
|
||||||
|
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major-aws-lambda-${arch[1]}")
|
||||||
|
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor-aws-lambda-${arch[1]}")
|
||||||
|
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$major.$minor.$patch-aws-lambda-${arch[1]}")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "Non-semver version detected, fallback to $version"
|
||||||
|
|
||||||
|
tags+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-${arch[1]}")
|
||||||
|
if [ "$platform" = "linux/amd64" ]; then
|
||||||
|
tags_cloud_run+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-cloudrun")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
|
||||||
|
tags_aws_lambda+=("$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version-aws-lambda-${arch[1]}")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
tags_flags=()
|
||||||
|
tags_cloud_run_flags=()
|
||||||
|
tags_aws_lambda_flags=()
|
||||||
|
|
||||||
|
echo "Will use the following tags:"
|
||||||
|
for tag in "${tags[@]}"; do
|
||||||
|
tags_flags+=("-t" "$tag")
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
for tag in "${tags_cloud_run[@]}"; do
|
||||||
|
tags_cloud_run_flags+=("-t" "$tag")
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
for tag in "${tags_aws_lambda[@]}"; do
|
||||||
|
tags_aws_lambda_flags+=("-t" "$tag")
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Build images.
|
||||||
|
run_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run - would run the following command:"
|
||||||
|
echo "$cmd"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "⚙️ Running command:"
|
||||||
|
echo "$cmd"
|
||||||
|
eval "$cmd"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
join() {
|
||||||
|
local delimiter="$1"
|
||||||
|
shift
|
||||||
|
local IFS="$delimiter"
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
no_arch_tag="$DOCKER_REGISTRY/$DOCKER_REPOSITORY:$version"
|
||||||
|
|
||||||
|
cmd="docker buildx build \
|
||||||
|
--build-arg GOTENBERG_VERSION=$version \
|
||||||
|
--platform $platform \
|
||||||
|
--load \
|
||||||
|
${tags_flags[*]} \
|
||||||
|
-t $no_arch_tag \
|
||||||
|
-f $DOCKERFILE $DOCKER_BUILD_CONTEXT
|
||||||
|
"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
|
||||||
|
if [ "$platform" = "linux/amd64" ]; then
|
||||||
|
cmd="docker build \
|
||||||
|
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
|
||||||
|
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
|
||||||
|
--build-arg GOTENBERG_VERSION=$version \
|
||||||
|
${tags_cloud_run_flags[*]} \
|
||||||
|
-f $DOCKERFILE_CLOUDRUN $DOCKER_BUILD_CONTEXT
|
||||||
|
"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$platform" = "linux/amd64" ] || [ "$platform" = "linux/arm64" ]; then
|
||||||
|
cmd="docker build \
|
||||||
|
--build-arg DOCKER_REGISTRY=$DOCKER_REGISTRY \
|
||||||
|
--build-arg DOCKER_REPOSITORY=$DOCKER_REPOSITORY \
|
||||||
|
--build-arg GOTENBERG_VERSION=$version \
|
||||||
|
${tags_aws_lambda_flags[*]} \
|
||||||
|
-f $DOCKERFILE_AWS_LAMBDA $DOCKER_BUILD_CONTEXT
|
||||||
|
"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Done!"
|
||||||
|
echo "tags=$(join "," "${tags[@]}")" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tags_cloud_run=$(join "," "${tags_cloud_run[@]}")" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tags_aws_lambda=$(join "," "${tags_aws_lambda[@]}")" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
76
.github/actions/build-test-push/push.sh
vendored
Executable file
76
.github/actions/build-test-push/push.sh
vendored
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit early.
|
||||||
|
# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source dot env file.
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
tags=""
|
||||||
|
dry_run=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tags)
|
||||||
|
tags="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
dry_run=$2
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Push tag(s) 📦"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "Tag(s) to push:"
|
||||||
|
IFS=',' read -ra tmp_tags_to_push <<< "$tags"
|
||||||
|
|
||||||
|
tags_to_push=()
|
||||||
|
for tag in "${tmp_tags_to_push[@]}"; do
|
||||||
|
[ -n "$tag" ] && tags_to_push+=("$tag")
|
||||||
|
done
|
||||||
|
|
||||||
|
for tag in "${tags_to_push[@]}"; do
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Push tags.
|
||||||
|
run_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run - would run the following command:"
|
||||||
|
echo "$cmd"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "⚙️ Running command:"
|
||||||
|
echo "$cmd"
|
||||||
|
eval "$cmd"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag in "${tags_to_push[@]}"; do
|
||||||
|
cmd="docker push $tag"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
|
||||||
|
echo "➡️ $tag pushed"
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Done!"
|
||||||
|
exit 0
|
||||||
79
.github/actions/build-test-push/test.sh
vendored
Executable file
79
.github/actions/build-test-push/test.sh
vendored
Executable file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit early.
|
||||||
|
# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source dot env file.
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
version=""
|
||||||
|
platform=""
|
||||||
|
alternate_repository=""
|
||||||
|
dry_run=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--version)
|
||||||
|
version="${2//v/}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--platform)
|
||||||
|
platform="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--alternate-repository)
|
||||||
|
alternate_repository="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
dry_run="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Integration testing 🧪"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "Gotenberg version: $version"
|
||||||
|
echo "Target platform: $platform"
|
||||||
|
|
||||||
|
repository=$DOCKER_REPOSITORY
|
||||||
|
|
||||||
|
if [ -n "$alternate_repository" ]; then
|
||||||
|
echo "⚠️ Using $alternate_repository for DOCKER_REPOSITORY"
|
||||||
|
repository=$alternate_repository
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Test image.
|
||||||
|
run_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run - would run the following command:"
|
||||||
|
echo "$cmd"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "⚙️ Running command:"
|
||||||
|
echo "$cmd"
|
||||||
|
eval "$cmd"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd="make test-integration DOCKER_REPOSITORY=$repository GOTENBERG_VERSION=$version PLATFORM=$platform NO_CONCURRENCY=true"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
|
||||||
|
echo "✅ Done!"
|
||||||
|
exit 0
|
||||||
31
.github/actions/clean/action.yml
vendored
Normal file
31
.github/actions/clean/action.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: Clean
|
||||||
|
description: Clean tags from Docker Hub
|
||||||
|
author: Julien Neuhart
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
docker_hub_username:
|
||||||
|
description: The Docker Hub username
|
||||||
|
required: true
|
||||||
|
docker_hub_password:
|
||||||
|
description: The Docker Hub password
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
description: Comma separated list of tags to clean
|
||||||
|
snapshot_version:
|
||||||
|
description: Snapshot version to clean
|
||||||
|
dry_run:
|
||||||
|
description: Dry run this action
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Clean tags from Docker Hub
|
||||||
|
env:
|
||||||
|
DOCKERHUB_USERNAME: ${{ inputs.docker_hub_username }}
|
||||||
|
DOCKERHUB_TOKEN: ${{ inputs.docker_hub_password }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
.github/actions/clean/clean.sh \
|
||||||
|
--tags "${{ inputs.tags }}" \
|
||||||
|
--snapshot-version "${{ inputs.snapshot_version }}" \
|
||||||
|
--dry-run "${{ inputs.dry_run }}"
|
||||||
123
.github/actions/clean/clean.sh
vendored
Executable file
123
.github/actions/clean/clean.sh
vendored
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit early.
|
||||||
|
# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source dot env file.
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
tags=""
|
||||||
|
snapshot_version=""
|
||||||
|
dry_run=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tags)
|
||||||
|
tags="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--snapshot-version)
|
||||||
|
snapshot_version="${2//v/}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
dry_run="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Clean tag(s) from Docker Hub 🧹"
|
||||||
|
echo
|
||||||
|
|
||||||
|
IFS=',' read -ra tags_to_delete <<< "$tags"
|
||||||
|
if [ -n "$snapshot_version" ]; then
|
||||||
|
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version")
|
||||||
|
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-cloudrun")
|
||||||
|
tags_to_delete+=("$DOCKER_REGISTRY/snapshot:$snapshot_version-aws-lambda")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Will delete the following tag(s):"
|
||||||
|
for tag in "${tags_to_delete[@]}"; do
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Delete tags.
|
||||||
|
base_url="https://hub.docker.com/v2"
|
||||||
|
token=""
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
token="placeholder"
|
||||||
|
echo "🚧 Dry run - would call $base_url to get a token"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "🌐 Get token from $base_url"
|
||||||
|
|
||||||
|
readarray -t lines < <(
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"username\":\"$DOCKERHUB_USERNAME\", \"password\":\"$DOCKERHUB_TOKEN\"}" \
|
||||||
|
-w "\n%{http_code}" \
|
||||||
|
"$base_url/users/login"
|
||||||
|
)
|
||||||
|
|
||||||
|
http_code="${lines[-1]}"
|
||||||
|
unset 'lines[-1]'
|
||||||
|
json_body=$(printf "%s\n" "${lines[@]}")
|
||||||
|
|
||||||
|
if [ "$http_code" -ne "200" ]; then
|
||||||
|
echo "❌ Wrong HTTP status - $http_code"
|
||||||
|
echo "$json_body"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
token=$(jq -r '.token' <<< "$json_body")
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$token" ]; then
|
||||||
|
echo "❌ No token from Docker Hub"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tag in "${tags_to_delete[@]}"; do
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run - would call $base_url to delete tag $tag"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "🌐 Delete tag $tag"
|
||||||
|
IFS=':' read -ra tag_parts <<< "$tag"
|
||||||
|
|
||||||
|
readarray -t lines < <(
|
||||||
|
curl -s -X DELETE \
|
||||||
|
-H "Authorization: Bearer $token" \
|
||||||
|
-w "\n%{http_code}" \
|
||||||
|
"$base_url/repositories/${tag_parts[0]}/tags/${tag_parts[1]}/"
|
||||||
|
)
|
||||||
|
|
||||||
|
http_code="${lines[-1]}"
|
||||||
|
unset 'lines[-1]'
|
||||||
|
|
||||||
|
if [ "$http_code" -ne "200" ] && [ "$http_code" -ne "204" ]; then
|
||||||
|
echo "❌ Wrong HTTP status - $http_code"
|
||||||
|
printf '%s\n' "${lines[@]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Done!"
|
||||||
|
exit 0
|
||||||
48
.github/actions/merge/action.yml
vendored
Normal file
48
.github/actions/merge/action.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: Merge
|
||||||
|
description: Merge tags to single multi-platform tags
|
||||||
|
author: Julien Neuhart
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
github_token:
|
||||||
|
description: The GitHub token
|
||||||
|
required: true
|
||||||
|
default: ${{ github.token }}
|
||||||
|
docker_hub_username:
|
||||||
|
description: The Docker Hub username
|
||||||
|
required: true
|
||||||
|
docker_hub_password:
|
||||||
|
description: The Docker Hub password
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
description: Comma separated tags to merge
|
||||||
|
required: true
|
||||||
|
alternate_registry:
|
||||||
|
description: Alternate registry to also push resulting tags
|
||||||
|
dry_run:
|
||||||
|
description: Dry run this action
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ inputs.docker_hub_username }}
|
||||||
|
password: ${{ inputs.docker_hub_password }}
|
||||||
|
|
||||||
|
- name: Merge
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
.github/actions/merge/merge.sh \
|
||||||
|
--tags "${{ inputs.tags }}" \
|
||||||
|
--alternate-registry "${{ inputs.alternate_registry }}" \
|
||||||
|
--dry-run "${{ inputs.dry_run }}"
|
||||||
108
.github/actions/merge/merge.sh
vendored
Executable file
108
.github/actions/merge/merge.sh
vendored
Executable file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit early.
|
||||||
|
# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source dot env file.
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
tags=""
|
||||||
|
alternate_registry=""
|
||||||
|
dry_run=""
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tags)
|
||||||
|
tags="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--alternate-registry)
|
||||||
|
alternate_registry="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
dry_run=$2
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Merge tag(s) 👷"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "Tag(s) to merge:"
|
||||||
|
IFS=',' read -ra tags_to_merge <<< "$tags"
|
||||||
|
for tag in "${tags_to_merge[@]}"; do
|
||||||
|
echo "- $tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$alternate_registry" ]; then
|
||||||
|
echo "⚠️ Will also push to $alternate_registry registry"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Build merge map.
|
||||||
|
declare -A merge_map
|
||||||
|
|
||||||
|
for tag in "${tags_to_merge[@]}"; do
|
||||||
|
target_tag="${tag//-amd64/}"
|
||||||
|
target_tag="${target_tag//-ppc64le/}"
|
||||||
|
target_tag="${target_tag//-arm64/}"
|
||||||
|
target_tag="${target_tag//-arm/}"
|
||||||
|
target_tag="${target_tag//-386/}"
|
||||||
|
|
||||||
|
merge_map["$target_tag"]+="$tag "
|
||||||
|
done
|
||||||
|
|
||||||
|
# Merge tags.
|
||||||
|
run_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
if [ "$dry_run" = "true" ]; then
|
||||||
|
echo "🚧 Dry run - would run the following command:"
|
||||||
|
echo "$cmd"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo "⚙️ Running command:"
|
||||||
|
echo "$cmd"
|
||||||
|
eval "$cmd"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for target in "${!merge_map[@]}"; do
|
||||||
|
IFS=' ' read -ra source_tags <<< "${merge_map[$target]}"
|
||||||
|
|
||||||
|
cmd="docker buildx imagetools create \
|
||||||
|
-t $target \
|
||||||
|
${source_tags[*]}
|
||||||
|
"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
|
||||||
|
echo "➡️ $target pushed"
|
||||||
|
echo
|
||||||
|
if [ -n "$alternate_registry" ]; then
|
||||||
|
alternate_target="${target/$DOCKER_REGISTRY/$alternate_registry}"
|
||||||
|
cmd="docker buildx imagetools create \
|
||||||
|
-t $alternate_target \
|
||||||
|
$target
|
||||||
|
"
|
||||||
|
run_cmd "$cmd"
|
||||||
|
|
||||||
|
echo "➡️ $alternate_target pushed"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Done!"
|
||||||
|
exit 0
|
||||||
14
.github/dependabot.yml
vendored
14
.github/dependabot.yml
vendored
@@ -1,8 +1,18 @@
|
|||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
|
|
||||||
# Maintain dependencies for GitHub Actions
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "/build"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
|||||||
6
.github/stale.yml
vendored
6
.github/stale.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
# Number of days of inactivity before an issue becomes stale
|
||||||
daysUntilStale: 15
|
daysUntilStale: 7
|
||||||
# Number of days of inactivity before a stale issue is closed
|
# Number of days of inactivity before a stale issue is closed
|
||||||
daysUntilClose: 7
|
daysUntilClose: 3
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- bug
|
- bug
|
||||||
@@ -15,4 +15,4 @@ markComment: >
|
|||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
for your contributions.
|
for your contributions.
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
closeComment: false
|
closeComment: false
|
||||||
|
|||||||
150
.github/workflows/continuous-delivery.yml
vendored
Normal file
150
.github/workflows/continuous-delivery.yml
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
name: Continuous Delivery
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release_amd64:
|
||||||
|
name: Release linux/amd64
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
platform: linux/amd64
|
||||||
|
skip_integrations_tests: true
|
||||||
|
|
||||||
|
release_386:
|
||||||
|
name: Release linux/386
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
platform: linux/386
|
||||||
|
skip_integrations_tests: true
|
||||||
|
|
||||||
|
release_ppc64le:
|
||||||
|
name: Release linux/ppc64le
|
||||||
|
runs-on: ubuntu-24.04-ppc64le
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
platform: linux/ppc64le
|
||||||
|
skip_integrations_tests: true
|
||||||
|
|
||||||
|
release_arm64:
|
||||||
|
name: Release linux/arm64
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
platform: linux/arm64
|
||||||
|
skip_integrations_tests: true
|
||||||
|
|
||||||
|
release_arm_v7:
|
||||||
|
name: Release linux/arm/v7
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
platform: linux/arm/v7
|
||||||
|
skip_integrations_tests: true
|
||||||
|
|
||||||
|
merge_clean_release_tags:
|
||||||
|
needs:
|
||||||
|
- release_amd64
|
||||||
|
- release_386
|
||||||
|
- release_ppc64le
|
||||||
|
- release_arm64
|
||||||
|
- release_arm_v7
|
||||||
|
name: Merge and clean release tags
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Merge
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_ppc64le.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }}"
|
||||||
|
alternate_registry: thecodingmachine
|
||||||
|
|
||||||
|
- name: Merge AWS Lambda
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"
|
||||||
|
alternate_registry: thecodingmachine
|
||||||
|
|
||||||
|
- name: Clean
|
||||||
|
uses: ./.github/actions/clean
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.release_amd64.outputs.tags }},${{ needs.release_386.outputs.tags }},${{ needs.release_ppc64le.outputs.tags }},${{ needs.release_arm64.outputs.tags }},${{ needs.release_arm_v7.outputs.tags }},${{ needs.release_amd64.outputs.tags_aws_lambda }},${{ needs.release_arm64.outputs.tags_aws_lambda }}"
|
||||||
398
.github/workflows/continuous-integration.yml
vendored
Normal file
398
.github/workflows/continuous-integration.yml
vendored
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
name: Continuous Integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ (github.event_name == 'pull_request' && github.event.pull_request.number) || 'main' }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint Golang codebase
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Run linters
|
||||||
|
uses: golangci/golangci-lint-action@v9
|
||||||
|
with:
|
||||||
|
version: v2.10.1
|
||||||
|
|
||||||
|
lint-prettier:
|
||||||
|
name: Lint non-Golang codebase
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm i
|
||||||
|
|
||||||
|
- name: Run linters
|
||||||
|
run: make lint-prettier
|
||||||
|
|
||||||
|
test-unit:
|
||||||
|
needs:
|
||||||
|
- lint
|
||||||
|
- lint-prettier
|
||||||
|
name: Run unit tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: make test-unit
|
||||||
|
|
||||||
|
snapshot_amd64:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Snapshot linux/amd64
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: pr-${{ github.event.pull_request.number }}
|
||||||
|
platform: linux/amd64
|
||||||
|
alternate_repository: snapshot
|
||||||
|
|
||||||
|
snapshot_ppc64le:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Snapshot linux/ppc64le
|
||||||
|
runs-on: ubuntu-24.04-ppc64le
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: pr-${{ github.event.pull_request.number }}
|
||||||
|
platform: linux/ppc64le
|
||||||
|
alternate_repository: snapshot
|
||||||
|
|
||||||
|
snapshot_386:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Snapshot linux/386
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: pr-${{ github.event.pull_request.number }}
|
||||||
|
platform: linux/386
|
||||||
|
alternate_repository: snapshot
|
||||||
|
|
||||||
|
snapshot_arm64:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Snapshot linux/arm64
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: pr-${{ github.event.pull_request.number }}
|
||||||
|
platform: linux/arm64
|
||||||
|
alternate_repository: snapshot
|
||||||
|
|
||||||
|
snapshot_arm_v7:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Snapshot linux/arm/v7
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: pr-${{ github.event.pull_request.number }}
|
||||||
|
platform: linux/arm/v7
|
||||||
|
alternate_repository: snapshot
|
||||||
|
|
||||||
|
merge_clean_snapshot_guard:
|
||||||
|
needs:
|
||||||
|
- snapshot_amd64
|
||||||
|
- snapshot_386
|
||||||
|
- snapshot_ppc64le
|
||||||
|
- snapshot_arm64
|
||||||
|
- snapshot_arm_v7
|
||||||
|
name: Secrets access check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
continue: ${{ steps.check.outputs.continue }}
|
||||||
|
steps:
|
||||||
|
- name: Check
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
if [ -n "${{ secrets.DOCKERHUB_USERNAME }}" ]; then
|
||||||
|
echo "continue=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "continue=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
merge_clean_snapshot_tags:
|
||||||
|
if: needs.merge_clean_snapshot_guard.outputs.continue == 'true'
|
||||||
|
needs:
|
||||||
|
- merge_clean_snapshot_guard
|
||||||
|
- snapshot_amd64
|
||||||
|
- snapshot_386
|
||||||
|
- snapshot_ppc64le
|
||||||
|
- snapshot_arm64
|
||||||
|
- snapshot_arm_v7
|
||||||
|
name: Merge and clean snapshot tags
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Merge
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_ppc64le.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }}"
|
||||||
|
|
||||||
|
- name: Merge AWS Lambda
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
|
||||||
|
|
||||||
|
- name: Clean
|
||||||
|
uses: ./.github/actions/clean
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.snapshot_amd64.outputs.tags }},${{ needs.snapshot_386.outputs.tags }},${{ needs.snapshot_ppc64le.outputs.tags }},${{ needs.snapshot_arm64.outputs.tags }},${{ needs.snapshot_arm_v7.outputs.tags }},${{ needs.snapshot_amd64.outputs.tags_aws_lambda }},${{ needs.snapshot_arm64.outputs.tags_aws_lambda }}"
|
||||||
|
|
||||||
|
edge_amd64:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Edge linux/amd64
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: edge
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
|
edge_386:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Edge linux/386
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: edge
|
||||||
|
platform: linux/386
|
||||||
|
|
||||||
|
edge_ppc64le:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Edge linux/ppc64le
|
||||||
|
runs-on: ubuntu-24.04-ppc64le
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: edge
|
||||||
|
platform: linux/ppc64le
|
||||||
|
|
||||||
|
edge_arm64:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Edge linux/arm64
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: edge
|
||||||
|
platform: linux/arm64
|
||||||
|
|
||||||
|
edge_arm_v7:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- test-unit
|
||||||
|
name: Edge linux/arm/v7
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
tags: ${{ steps.build_test_push.outputs.tags }}
|
||||||
|
tags_cloud_run: ${{ steps.build_test_push.outputs.tags_cloud_run }}
|
||||||
|
tags_aws_lambda: ${{ steps.build_test_push.outputs.tags_aws_lambda }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Build, test and push
|
||||||
|
id: build_test_push
|
||||||
|
uses: ./.github/actions/build-test-push
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
version: edge
|
||||||
|
platform: linux/arm/v7
|
||||||
|
|
||||||
|
merge_clean_edge_tags:
|
||||||
|
needs:
|
||||||
|
- edge_amd64
|
||||||
|
- edge_386
|
||||||
|
- edge_ppc64le
|
||||||
|
- edge_arm64
|
||||||
|
- edge_arm_v7
|
||||||
|
name: Merge and clean edge tags
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Merge
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_ppc64le.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }}"
|
||||||
|
alternate_registry: thecodingmachine
|
||||||
|
|
||||||
|
- name: Merge AWS Lambda
|
||||||
|
uses: ./.github/actions/merge
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"
|
||||||
|
alternate_registry: thecodingmachine
|
||||||
|
|
||||||
|
- name: Clean
|
||||||
|
uses: ./.github/actions/clean
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
tags: "${{ needs.edge_amd64.outputs.tags }},${{ needs.edge_386.outputs.tags }},${{ needs.edge_ppc64le.outputs.tags }},${{ needs.edge_arm64.outputs.tags }},${{ needs.edge_arm_v7.outputs.tags }},${{ needs.edge_amd64.outputs.tags_aws_lambda }},${{ needs.edge_arm64.outputs.tags_aws_lambda }}"
|
||||||
26
.github/workflows/continuous_delivery.yml
vendored
26
.github/workflows/continuous_delivery.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: Continuous Delivery
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [ published ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Release Docker image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Log in to Docker Hub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Build and push Docker image for release
|
|
||||||
run: |
|
|
||||||
make release GOTENBERG_VERSION=${{ github.event.release.tag_name }}
|
|
||||||
make release GOTENBERG_VERSION=${{ github.event.release.tag_name }} DOCKER_REPOSITORY=thecodingmachine
|
|
||||||
71
.github/workflows/continuous_integration.yml
vendored
71
.github/workflows/continuous_integration.yml
vendored
@@ -1,71 +0,0 @@
|
|||||||
name: Continuous Integration
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
lint:
|
|
||||||
name: Lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.21'
|
|
||||||
cache: false
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Run linters
|
|
||||||
uses: golangci/golangci-lint-action@v4
|
|
||||||
with:
|
|
||||||
version: v1.55.2
|
|
||||||
|
|
||||||
tests:
|
|
||||||
needs:
|
|
||||||
- Lint
|
|
||||||
name: Tests
|
|
||||||
# TODO: once arm64 actions are available, also run the tests on this architecture.
|
|
||||||
# See: https://github.com/actions/virtual-environments/issues/2552#issuecomment-771478000.
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Build testing environment
|
|
||||||
run: make build build-tests
|
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
make tests-once
|
|
||||||
bash <(curl -s https://codecov.io/bash)
|
|
||||||
|
|
||||||
multiarch_build:
|
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
||||||
needs:
|
|
||||||
- Tests
|
|
||||||
name: Multi-arch build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Log in to Docker Hub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Build and push Docker image for main branch
|
|
||||||
run: |
|
|
||||||
make release GOTENBERG_VERSION=edge
|
|
||||||
make release GOTENBERG_VERSION=edge DOCKER_REPOSITORY=thecodingmachine
|
|
||||||
24
.github/workflows/pull-request-cleanup.yml
vendored
Normal file
24
.github/workflows/pull-request-cleanup.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Pull Request Cleanup
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cleanup:
|
||||||
|
name: Cleanup Docker images
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
uses: ./.github/actions/clean
|
||||||
|
with:
|
||||||
|
docker_hub_username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
docker_hub_password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
snapshot_version: pr-${{ github.event.pull_request.number }}
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/coverage.html
|
.idea
|
||||||
/coverage.txt
|
.vscode
|
||||||
/TODO.txt
|
.DS_Store
|
||||||
|
/node_modules/
|
||||||
|
|||||||
@@ -1,36 +1,65 @@
|
|||||||
linters-settings:
|
version: "2"
|
||||||
gci:
|
run:
|
||||||
sections:
|
issues-exit-code: 1
|
||||||
- standard
|
tests: false
|
||||||
- default
|
|
||||||
- prefix(github.com/gotenberg/gotenberg/v8)
|
|
||||||
skip-generated: true
|
|
||||||
custom-order: true
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
default: none
|
||||||
enable:
|
enable:
|
||||||
|
- asasalint
|
||||||
|
- asciicheck
|
||||||
|
- bidichk
|
||||||
- bodyclose
|
- bodyclose
|
||||||
|
- copyloopvar
|
||||||
|
- decorder
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- dupword
|
||||||
|
- durationcheck
|
||||||
- errcheck
|
- errcheck
|
||||||
- gci
|
- errname
|
||||||
- gofumpt
|
- exhaustive
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
|
||||||
- govet
|
- govet
|
||||||
|
- importas
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- misspell
|
- misspell
|
||||||
- prealloc
|
- prealloc
|
||||||
|
- promlinter
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- typecheck
|
- testableexamples
|
||||||
|
- tparallel
|
||||||
- unconvert
|
- unconvert
|
||||||
- unused
|
- unused
|
||||||
|
- usetesting
|
||||||
run:
|
- wastedassign
|
||||||
timeout: 5m
|
- whitespace
|
||||||
issues-exit-code: 1
|
exclusions:
|
||||||
tests: false
|
generated: lax
|
||||||
|
presets:
|
||||||
output:
|
- comments
|
||||||
format: 'colored-line-number'
|
- common-false-positives
|
||||||
print-issued-lines: true
|
- legacy
|
||||||
print-linter-name: true
|
- std-error-handling
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gci
|
||||||
|
- gofmt
|
||||||
|
- gofumpt
|
||||||
|
- goimports
|
||||||
|
settings:
|
||||||
|
gci:
|
||||||
|
sections:
|
||||||
|
- standard
|
||||||
|
- default
|
||||||
|
- prefix(github.com/gotenberg/gotenberg/v8)
|
||||||
|
custom-order: true
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
|||||||
1
.node-version
Normal file
1
.node-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
24.11.0
|
||||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build
|
||||||
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-gherkin", "prettier-plugin-sh"],
|
||||||
|
"escapeBackslashes": true
|
||||||
|
}
|
||||||
66
AGENTS.md
Normal file
66
AGENTS.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Operational Guidelines for Gotenberg
|
||||||
|
|
||||||
|
As an AI agent working on the Gotenberg repository, you are expected to act with the diligence and architectural foresight of a Senior Go Engineer. Gotenberg is a widely used production dependency; stability and backward compatibility are paramount.
|
||||||
|
|
||||||
|
## 1. Core Philosophy & Stability
|
||||||
|
|
||||||
|
- **Backward Compatibility is Law:** This project creates a public API. Never modify existing flags, configuration environment variables, or API form fields unless explicitly instructed to perform a breaking change. If a change is breaking, it must be flagged immediately in the plan.
|
||||||
|
- **Defensive Programming:** Assume input data is malformed. Handle errors explicitly. Do not panic.
|
||||||
|
- **Atomic Commits:** Isolate refactoring from feature additions. A Pull Request should do one thing well.
|
||||||
|
|
||||||
|
## 2. Development Workflow & Tooling
|
||||||
|
|
||||||
|
You must rely strictly on the project's Makefile for build and verification tasks. Do not run `go` commands directly unless debugging a specific package requires it.
|
||||||
|
|
||||||
|
- **Formatting:** Run `make fmt` to format Go code before committing.
|
||||||
|
- **Linting:**
|
||||||
|
- Run `make lint` to ensure Go code strictly adheres to the `.golangci.yml` configuration.
|
||||||
|
- Run `make lint-prettier` to verify formatting for non-Go files (Markdown, YAML, etc.).
|
||||||
|
- Zero linting errors are permitted.
|
||||||
|
- **Building:** Run `make build` to verify compilation and Docker image construction.
|
||||||
|
|
||||||
|
## 3. Architecture & Code Structure
|
||||||
|
|
||||||
|
- **Idiomatic Go:** Follow "Effective Go" principles.
|
||||||
|
- **Directory Separation:**
|
||||||
|
- `cmd/`: Application entry points only. Contains wiring and startup logic. **No business logic is permitted here.**
|
||||||
|
- `pkg/`: Core library code and modules. All business logic resides here.
|
||||||
|
- **Module System:** Gotenberg is modular (e.g., Chromium, LibreOffice). When adding features, determine if they belong to an existing module or require a new strict isolation.
|
||||||
|
|
||||||
|
## 4. Testing Standards
|
||||||
|
|
||||||
|
Gotenberg utilizes a split testing strategy. **Integration tests are the primary and preferred method for verifying features.**
|
||||||
|
|
||||||
|
- **Integration Tests (`make test-integration`):**
|
||||||
|
- **First Priority:** Always start here when adding features or routes.
|
||||||
|
- Gotenberg uses **Gherkin (Godog)** for end-to-end verification.
|
||||||
|
- You **must** create or update the corresponding `.feature` file in `test/integration`.
|
||||||
|
- These tests run within the Docker context; ensure environment consistency.
|
||||||
|
- **Unit Tests (`make test-unit`):**
|
||||||
|
- Use table-driven tests for pure logic within `pkg/`.
|
||||||
|
- Mock external dependencies (filesystem, network) where appropriate.
|
||||||
|
|
||||||
|
## 5. Documentation Requirements
|
||||||
|
|
||||||
|
- **No README Updates:** Do not modify the root `README.md` unless explicitly asked.
|
||||||
|
- **GoDoc is Mandatory:**
|
||||||
|
- **New Packages:** If creating a new package, you must include a `doc.go` file containing the package-level documentation.
|
||||||
|
- **Exported Symbols:** Every exported function, type, constant, and variable must have a proper GoDoc comment starting with its name.
|
||||||
|
- **Quality:** Comments must be complete sentences explaining _what_ the symbol does and _how_ to use it.
|
||||||
|
- **Example:**
|
||||||
|
```go
|
||||||
|
// Convert transforms the input document to PDF using the Chromium engine.
|
||||||
|
// It returns an error if the connection to the browser instance fails.
|
||||||
|
func Convert(...) error
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Definition of Done
|
||||||
|
|
||||||
|
A task is considered complete only when:
|
||||||
|
|
||||||
|
1. The code compiles via `make build`.
|
||||||
|
2. The code is formatted via `make fmt`.
|
||||||
|
3. All linters pass via `make lint` and `make lint-prettier`.
|
||||||
|
4. Integration scenarios pass via `make test-integration`.
|
||||||
|
5. Unit tests pass via `make test-unit`.
|
||||||
|
6. All exported symbols and new packages have compliant GoDoc.
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 Julien Neuhart
|
Copyright (c) Julien Neuhart
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
240
Makefile
240
Makefile
@@ -1,44 +1,44 @@
|
|||||||
|
include .env
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help: ## Show the help
|
help: ## Show the help
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@grep -hE '^[A-Za-z0-9_ \-]*?:.*##.*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
.PHONY: it
|
|
||||||
it: build build-tests ## Initialize the development environment
|
|
||||||
|
|
||||||
GOLANG_VERSION=1.21
|
|
||||||
DOCKER_REPOSITORY=gotenberg
|
|
||||||
GOTENBERG_VERSION=snapshot
|
|
||||||
GOTENBERG_USER_GID=1001
|
|
||||||
GOTENBERG_USER_UID=1001
|
|
||||||
NOTO_COLOR_EMOJI_VERSION=v2.042 # See https://github.com/googlefonts/noto-emoji/releases.
|
|
||||||
PDFTK_VERSION=v3.3.3 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
|
|
||||||
GOLANGCI_LINT_VERSION=v1.55.2 # See https://github.com/golangci/golangci-lint/releases.
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: ## Build the Gotenberg's Docker image
|
build: ## Build the Gotenberg's Docker image
|
||||||
docker build \
|
docker build \
|
||||||
--build-arg GOLANG_VERSION=$(GOLANG_VERSION) \
|
-t $(DOCKER_REGISTRY)/$(DOCKER_REPOSITORY):$(GOTENBERG_VERSION) \
|
||||||
--build-arg GOTENBERG_VERSION=$(GOTENBERG_VERSION) \
|
-f $(DOCKERFILE) $(DOCKER_BUILD_CONTEXT)
|
||||||
--build-arg GOTENBERG_USER_GID=$(GOTENBERG_USER_GID) \
|
|
||||||
--build-arg GOTENBERG_USER_UID=$(GOTENBERG_USER_UID) \
|
|
||||||
--build-arg NOTO_COLOR_EMOJI_VERSION=$(NOTO_COLOR_EMOJI_VERSION) \
|
|
||||||
--build-arg PDFTK_VERSION=$(PDFTK_VERSION) \
|
|
||||||
-t $(DOCKER_REPOSITORY)/gotenberg:$(GOTENBERG_VERSION) \
|
|
||||||
-f build/Dockerfile .
|
|
||||||
|
|
||||||
|
TZ=UTC
|
||||||
|
GOTENBERG_HIDE_BANNER=false
|
||||||
GOTENBERG_GRACEFUL_SHUTDOWN_DURATION=30s
|
GOTENBERG_GRACEFUL_SHUTDOWN_DURATION=30s
|
||||||
|
GOTENBERG_BUILD_DEBUG_DATA=true
|
||||||
API_PORT=3000
|
API_PORT=3000
|
||||||
API_PORT_FROM_ENV=
|
API_PORT_FROM_ENV=
|
||||||
|
API_BIND_IP=
|
||||||
API_START_TIMEOUT=30s
|
API_START_TIMEOUT=30s
|
||||||
API_TIMEOUT=30s
|
API_TIMEOUT=30s
|
||||||
|
API_BODY_LIMIT=
|
||||||
API_ROOT_PATH=/
|
API_ROOT_PATH=/
|
||||||
API_TRACE_HEADER=Gotenberg-Trace
|
API_CORRELATION_ID_HEADER=Gotenberg-Trace
|
||||||
API_DISABLE_HEALTH_CHECK_LOGGING=false
|
API_ENABLE_BASIC_AUTH=false
|
||||||
CHROMIUM_RESTART_AFTER=0
|
GOTENBERG_API_BASIC_AUTH_USERNAME=
|
||||||
|
GOTENBERG_API_BASIC_AUTH_PASSWORD=
|
||||||
|
API_DOWNLOAD_FROM_ALLOW_LIST=
|
||||||
|
API_DOWNLOAD_FROM_DENY_LIST=
|
||||||
|
API_DOWNLOAD_FROM_MAX_RETRY=4
|
||||||
|
API_DISABLE_DOWNLOAD_FROM=false
|
||||||
|
API_DISABLE_HEALTH_CHECK_ROUTE_TELEMETRY=false
|
||||||
|
API_DISABLE_ROOT_ROUTE_TELEMETRY=false
|
||||||
|
API_DISABLE_VERSION_ROUTE_TELEMETRY=false
|
||||||
|
API_DISABLE_DEBUG_ROUTE_TELEMETRY=false
|
||||||
|
API_ENABLE_DEBUG_ROUTE=false
|
||||||
|
CHROMIUM_RESTART_AFTER=100
|
||||||
CHROMIUM_MAX_QUEUE_SIZE=0
|
CHROMIUM_MAX_QUEUE_SIZE=0
|
||||||
|
CHROMIUM_MAX_CONCURRENCY=6
|
||||||
CHROMIUM_AUTO_START=false
|
CHROMIUM_AUTO_START=false
|
||||||
CHROMIUM_START_TIMEOUT=20s
|
CHROMIUM_START_TIMEOUT=20s
|
||||||
CHROMIUM_INCOGNITO=false
|
|
||||||
CHROMIUM_ALLOW_INSECURE_LOCALHOST=false
|
CHROMIUM_ALLOW_INSECURE_LOCALHOST=false
|
||||||
CHROMIUM_IGNORE_CERTIFICATE_ERRORS=false
|
CHROMIUM_IGNORE_CERTIFICATE_ERRORS=false
|
||||||
CHROMIUM_DISABLE_WEB_SECURITY=false
|
CHROMIUM_DISABLE_WEB_SECURITY=false
|
||||||
@@ -57,14 +57,26 @@ LIBREOFFICE_AUTO_START=false
|
|||||||
LIBREOFFICE_START_TIMEOUT=20s
|
LIBREOFFICE_START_TIMEOUT=20s
|
||||||
LIBREOFFICE_DISABLE_ROUTES=false
|
LIBREOFFICE_DISABLE_ROUTES=false
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
LOG_FORMAT=auto
|
|
||||||
LOG_FIELDS_PREFIX=
|
LOG_FIELDS_PREFIX=
|
||||||
PDFENGINES_ENGINES=
|
LOG_STD_FORMAT=auto
|
||||||
|
LOG_STD_ENABLE_GCP_FIELDS=false
|
||||||
|
PDFENGINES_MERGE_ENGINES=qpdf,pdfcpu,pdftk
|
||||||
|
PDFENGINES_SPLIT_ENGINES=pdfcpu,qpdf,pdftk
|
||||||
|
PDFENGINES_FLATTEN_ENGINES=qpdf
|
||||||
|
PDFENGINES_CONVERT_ENGINES=libreoffice-pdfengine
|
||||||
|
PDFENGINES_READ_METADATA_ENGINES=exiftool
|
||||||
|
PDFENGINES_WRITE_METADATA_ENGINES=exiftool
|
||||||
|
PDFENGINES_ENCRYPT_ENGINES=qpdf,pdfcpu,pdftk
|
||||||
PDFENGINES_DISABLE_ROUTES=false
|
PDFENGINES_DISABLE_ROUTES=false
|
||||||
PROMETHEUS_NAMESPACE=gotenberg
|
PDFENGINES_ADD_ATTACHMENTS_ENGINES=pdfcpu
|
||||||
PROMETHEUS_COLLECT_INTERVAL=1s
|
OTEL_SERVICE_NAME=gotenberg
|
||||||
PROMETHEUS_DISABLE_ROUTE_LOGGING=false
|
OTEL_TRACES_EXPORTER=none
|
||||||
PROMETHEUS_DISABLE_COLLECT=false
|
OTEL_METRICS_EXPORTER=none
|
||||||
|
OTEL_LOGS_EXPORTER=none
|
||||||
|
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
|
||||||
|
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
|
||||||
|
OTEL_EXPORTER_OTLP_INSECURE=true
|
||||||
|
WEBHOOK_ENABLE_SYNC_MODE=false
|
||||||
WEBHOOK_ALLOW_LIST=
|
WEBHOOK_ALLOW_LIST=
|
||||||
WEBHOOK_DENY_LIST=
|
WEBHOOK_DENY_LIST=
|
||||||
WEBHOOK_ERROR_ALLOW_LIST=
|
WEBHOOK_ERROR_ALLOW_LIST=
|
||||||
@@ -75,106 +87,92 @@ WEBHOOK_RETRY_MAX_WAIT=30s
|
|||||||
WEBHOOK_CLIENT_TIMEOUT=30s
|
WEBHOOK_CLIENT_TIMEOUT=30s
|
||||||
WEBHOOK_DISABLE=false
|
WEBHOOK_DISABLE=false
|
||||||
|
|
||||||
|
# Export all variables so they are available to Compose
|
||||||
|
export
|
||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: ## Start a Gotenberg container
|
run: ## Start a Gotenberg container via Compose
|
||||||
docker run --rm -it \
|
docker compose up gotenberg
|
||||||
-p $(API_PORT):$(API_PORT) \
|
|
||||||
$(DOCKER_REPOSITORY)/gotenberg:$(GOTENBERG_VERSION) \
|
|
||||||
gotenberg \
|
|
||||||
--gotenberg-graceful-shutdown-duration=$(GOTENBERG_GRACEFUL_SHUTDOWN_DURATION) \
|
|
||||||
--api-port=$(API_PORT) \
|
|
||||||
--api-port-from-env=$(API_PORT_FROM_ENV) \
|
|
||||||
--api-start-timeout=$(API_START_TIMEOUT) \
|
|
||||||
--api-timeout=$(API_TIMEOUT) \
|
|
||||||
--api-root-path=$(API_ROOT_PATH) \
|
|
||||||
--api-trace-header=$(API_TRACE_HEADER) \
|
|
||||||
--api-disable-health-check-logging=$(API_DISABLE_HEALTH_CHECK_LOGGING) \
|
|
||||||
--chromium-restart-after=$(CHROMIUM_RESTART_AFTER) \
|
|
||||||
--chromium-auto-start=$(CHROMIUM_AUTO_START) \
|
|
||||||
--chromium-max-queue-size=$(CHROMIUM_MAX_QUEUE_SIZE) \
|
|
||||||
--chromium-start-timeout=$(CHROMIUM_START_TIMEOUT) \
|
|
||||||
--chromium-incognito=$(CHROMIUM_INCOGNITO) \
|
|
||||||
--chromium-allow-insecure-localhost=$(CHROMIUM_ALLOW_INSECURE_LOCALHOST) \
|
|
||||||
--chromium-ignore-certificate-errors=$(CHROMIUM_IGNORE_CERTIFICATE_ERRORS) \
|
|
||||||
--chromium-disable-web-security=$(CHROMIUM_DISABLE_WEB_SECURITY) \
|
|
||||||
--chromium-allow-file-access-from-files=$(CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES) \
|
|
||||||
--chromium-host-resolver-rules=$(CHROMIUM_HOST_RESOLVER_RULES) \
|
|
||||||
--chromium-proxy-server=$(CHROMIUM_PROXY_SERVER) \
|
|
||||||
--chromium-allow-list="$(CHROMIUM_ALLOW_LIST)" \
|
|
||||||
--chromium-deny-list="$(CHROMIUM_DENY_LIST)" \
|
|
||||||
--chromium-clear-cache=$(CHROMIUM_CLEAR_CACHE) \
|
|
||||||
--chromium-clear-cookies=$(CHROMIUM_CLEAR_COOKIES) \
|
|
||||||
--chromium-disable-javascript=$(CHROMIUM_DISABLE_JAVASCRIPT) \
|
|
||||||
--chromium-disable-routes=$(CHROMIUM_DISABLE_ROUTES) \
|
|
||||||
--libreoffice-restart-after=$(LIBREOFFICE_RESTART_AFTER) \
|
|
||||||
--libreoffice-max-queue-size=$(LIBREOFFICE_MAX_QUEUE_SIZE) \
|
|
||||||
--libreoffice-auto-start=$(LIBREOFFICE_AUTO_START) \
|
|
||||||
--libreoffice-start-timeout=$(LIBREOFFICE_START_TIMEOUT) \
|
|
||||||
--libreoffice-disable-routes=$(LIBREOFFICE_DISABLE_ROUTES) \
|
|
||||||
--log-level=$(LOG_LEVEL) \
|
|
||||||
--log-format=$(LOG_FORMAT) \
|
|
||||||
--log-fields-prefix=$(LOG_FIELDS_PREFIX) \
|
|
||||||
--pdfengines-engines=$(PDFENGINES_ENGINES) \
|
|
||||||
--pdfengines-disable-routes=$(PDFENGINES_DISABLE_ROUTES) \
|
|
||||||
--prometheus-namespace=$(PROMETHEUS_NAMESPACE) \
|
|
||||||
--prometheus-collect-interval=$(PROMETHEUS_COLLECT_INTERVAL) \
|
|
||||||
--prometheus-disable-route-logging=$(PROMETHEUS_DISABLE_ROUTE_LOGGING) \
|
|
||||||
--prometheus-disable-collect=$(PROMETHEUS_DISABLE_COLLECT) \
|
|
||||||
--webhook-allow-list="$(WEBHOOK_ALLOW_LIST)" \
|
|
||||||
--webhook-deny-list="$(WEBHOOK_DENY_LIST)" \
|
|
||||||
--webhook-error-allow-list=$(WEBHOOK_ERROR_ALLOW_LIST) \
|
|
||||||
--webhook-error-deny-list=$(WEBHOOK_ERROR_DENY_LIST) \
|
|
||||||
--webhook-max-retry=$(WEBHOOK_MAX_RETRY) \
|
|
||||||
--webhook-retry-min-wait=$(WEBHOOK_RETRY_MIN_WAIT) \
|
|
||||||
--webhook-retry-max-wait=$(WEBHOOK_RETRY_MAX_WAIT) \
|
|
||||||
--webhook-client-timeout=$(WEBHOOK_CLIENT_TIMEOUT) \
|
|
||||||
--webhook-disable=$(WEBHOOK_DISABLE)
|
|
||||||
|
|
||||||
.PHONY: build-tests
|
.PHONY: telemetry
|
||||||
build-tests: ## Build the tests' Docker image
|
telemetry: ## Start an OpenTelemetry collector and OpenObserve containers via Compose
|
||||||
docker build \
|
docker compose up otel-collector openobserve
|
||||||
--build-arg GOLANG_VERSION=$(GOLANG_VERSION) \
|
|
||||||
--build-arg DOCKER_REPOSITORY=$(DOCKER_REPOSITORY) \
|
|
||||||
--build-arg GOTENBERG_VERSION=$(GOTENBERG_VERSION) \
|
|
||||||
--build-arg GOLANGCI_LINT_VERSION=$(GOLANGCI_LINT_VERSION) \
|
|
||||||
-t $(DOCKER_REPOSITORY)/gotenberg:$(GOTENBERG_VERSION)-tests \
|
|
||||||
-f test/Dockerfile .
|
|
||||||
|
|
||||||
.PHONY: tests
|
.PHONY: down
|
||||||
tests: ## Start the testing environment
|
down: ## Stop all containers
|
||||||
docker run --rm -it \
|
docker compose down -v
|
||||||
-v $(PWD):/tests \
|
|
||||||
$(DOCKER_REPOSITORY)/gotenberg:$(GOTENBERG_VERSION)-tests \
|
|
||||||
bash
|
|
||||||
|
|
||||||
.PHONY: tests-once
|
.PHONY: test-unit
|
||||||
tests-once: ## Run the tests once (prefer the "tests" command while developing)
|
test-unit: ## Run unit tests
|
||||||
docker run --rm \
|
go test -race ./...
|
||||||
-v $(PWD):/tests \
|
|
||||||
$(DOCKER_REPOSITORY)/gotenberg:$(GOTENBERG_VERSION)-tests \
|
PLATFORM=
|
||||||
gotest
|
NO_CONCURRENCY=false
|
||||||
|
# Available tags:
|
||||||
|
# chromium
|
||||||
|
# chromium-concurrent
|
||||||
|
# chromium-convert-html
|
||||||
|
# chromium-convert-markdown
|
||||||
|
# chromium-convert-url
|
||||||
|
# debug
|
||||||
|
# health
|
||||||
|
# libreoffice
|
||||||
|
# libreoffice-convert
|
||||||
|
# output-filename
|
||||||
|
# pdfengines
|
||||||
|
# pdfengines-convert
|
||||||
|
# pdfengines-attachments
|
||||||
|
# attachments
|
||||||
|
# pdfengines-encrypt
|
||||||
|
# encrypt
|
||||||
|
# pdfengines-flatten
|
||||||
|
# flatten
|
||||||
|
# pdfengines-merge
|
||||||
|
# merge
|
||||||
|
# pdfengines-metadata
|
||||||
|
# metadata
|
||||||
|
# pdfengines-split
|
||||||
|
# split
|
||||||
|
# root
|
||||||
|
# version
|
||||||
|
# webhook
|
||||||
|
# download-from
|
||||||
|
# telemetry
|
||||||
|
TAGS=
|
||||||
|
|
||||||
|
.PHONY: test-integration
|
||||||
|
test-integration: ## Run integration tests
|
||||||
|
go test -timeout 40m -tags=integration -v github.com/gotenberg/gotenberg/v8/test/integration -args \
|
||||||
|
--gotenberg-docker-repository=$(DOCKER_REPOSITORY) \
|
||||||
|
--gotenberg-version=$(GOTENBERG_VERSION) \
|
||||||
|
--gotenberg-container-platform=$(PLATFORM) \
|
||||||
|
--no-concurrency=$(NO_CONCURRENCY) \
|
||||||
|
--tags="$(TAGS)"
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: ## Lint Golang codebase
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: lint-prettier
|
||||||
|
lint-prettier: ## Lint non-Golang codebase
|
||||||
|
npx prettier --check .
|
||||||
|
|
||||||
|
.PHONY: lint-todo
|
||||||
|
lint-todo: ## Find TODOs in Golang codebase
|
||||||
|
golangci-lint run --no-config --disable-all --enable godox
|
||||||
|
|
||||||
# go install mvdan.cc/gofumpt@latest
|
|
||||||
# go install github.com/daixiang0/gci@latest
|
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt: ## Format the code and "optimize" the dependencies
|
fmt: ## Format Golang codebase and "optimize" the dependencies
|
||||||
gofumpt -l -w .
|
go fix ./...
|
||||||
gci write -s standard -s default -s "prefix(github.com/gotenberg/gotenberg/v8)" --skip-generated --skip-vendor --custom-order .
|
golangci-lint fmt
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
||||||
|
.PHONY: prettify
|
||||||
|
prettify: ## Format non-Golang codebase
|
||||||
|
npx prettier --write .
|
||||||
|
|
||||||
# go install golang.org/x/tools/cmd/godoc@latest
|
# go install golang.org/x/tools/cmd/godoc@latest
|
||||||
.PHONY: godoc
|
.PHONY: godoc
|
||||||
godoc: ## Run a webserver with Gotenberg godoc
|
godoc: ## Run a webserver with Gotenberg godoc
|
||||||
$(info http://localhost:6060/pkg/github.com/gotenberg/gotenberg/v8)
|
$(info http://localhost:6060/pkg/github.com/gotenberg/gotenberg/v8)
|
||||||
godoc -http=:6060
|
godoc -http=:6060
|
||||||
|
|
||||||
.PHONY: release
|
|
||||||
release: ## Build the Gotenberg's Docker image for many platforms, then push it to a Docker repository
|
|
||||||
./scripts/release.sh \
|
|
||||||
$(GOLANG_VERSION) \
|
|
||||||
$(GOTENBERG_VERSION) \
|
|
||||||
$(GOTENBERG_USER_GID) \
|
|
||||||
$(GOTENBERG_USER_UID) \
|
|
||||||
$(NOTO_COLOR_EMOJI_VERSION) \
|
|
||||||
$(PDFTK_VERSION) \
|
|
||||||
$(DOCKER_REPOSITORY)
|
|
||||||
|
|||||||
54
README.md
54
README.md
@@ -1,45 +1,49 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://user-images.githubusercontent.com/8983173/130322857-185831e2-f041-46eb-a17f-0a69d066c4e5.png" alt="Gotenberg Logo" width="150" height="150" />
|
<img src="https://user-images.githubusercontent.com/8983173/130322857-185831e2-f041-46eb-a17f-0a69d066c4e5.png" alt="Gotenberg Logo" width="150" height="150" />
|
||||||
<h3 align="center">Gotenberg</h3>
|
<h3 align="center">Gotenberg</h3>
|
||||||
<p align="center">A Docker-powered stateless API for PDF files</p>
|
<p align="center">A containerized API for seamless PDF conversion</p>
|
||||||
<p align="center"><a href="https://gotenberg.dev/docs/getting-started/introduction">Documentation</a> · <a href="https://gotenberg.dev/docs/getting-started/installation#live-demo-">Live Demo</a> 🔥</p>
|
<p align="center">
|
||||||
|
<a href="https://hub.docker.com/r/gotenberg/gotenberg"><img alt="Total downloads (gotenberg/gotenberg)" src="https://img.shields.io/docker/pulls/gotenberg/gotenberg"></a>
|
||||||
|
<a href="https://github.com/gotenberg/gotenberg/actions/workflows/continuous-integration.yml"><img alt="Continuous Integration" src="https://github.com/gotenberg/gotenberg/actions/workflows/continuous-integration.yml/badge.svg"></a>
|
||||||
|
<a href="https://pkg.go.dev/github.com/gotenberg/gotenberg/v8"><img alt="Go Reference" src="https://pkg.go.dev/badge/github.com/gotenberg/gotenberg.svg"></a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://trendshift.io/repositories/2996"><img src="https://trendshift.io/api/badge/repositories/2996" alt="gotenberg%2Fgotenberg | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><a href="https://gotenberg.dev/docs/getting-started/introduction">Read the Documentation</a> · <a href="https://gotenberg.dev/docs/getting-started/installation#live-demo-">Try the Live Demo</a> 🔥</p>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Gotenberg provides a developer-friendly API to interact with powerful tools like Chromium and LibreOffice for converting
|
**Gotenberg** is a containerized API that abstracts the complexity of PDF conversion.
|
||||||
numerous document formats (HTML, Markdown, Word, Excel, etc.) into PDF files, and more!
|
|
||||||
|
It provides a `multipart/form-data` interface for interacting with powerful engines like Chromium and LibreOffice.
|
||||||
|
Instead of managing heavy dependencies, browser versions, or fonts in your own backend, simply send your files to
|
||||||
|
Gotenberg and get a PDF in return.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Open a terminal and run the following command:
|
Open a terminal and run the following command:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
docker run --rm -p 3000:3000 gotenberg/gotenberg:8
|
docker run --rm -p 3000:3000 gotenberg/gotenberg:8
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, using the historic Docker repository from our sponsor [TheCodingMachine](https://www.thecodingmachine.com):
|
With the API running at `http://localhost:3000`, you are now ready to head
|
||||||
|
to the **[Full Documentation](https://gotenberg.dev/docs/getting-started/introduction)** to discover how to convert URLs,
|
||||||
```
|
local files, inject custom CSS, merge PDFs, and more.
|
||||||
docker run --rm -p 3000:3000 thecodingmachine/gotenberg:8
|
|
||||||
```
|
|
||||||
|
|
||||||
The API is now available on your host at http://localhost:3000.
|
|
||||||
|
|
||||||
Head to the [documentation](https://gotenberg.dev/docs/getting-started/introduction) to learn how to interact with it 🚀
|
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
<p align="center">
|
Open-source development takes a significant amount of time, energy, and dedication. If Gotenberg helps streamline your
|
||||||
<a href="https://thecodingmachine.com">
|
workflow or powers your business, please consider supporting its continuous improvement by [**becoming a sponsor**](https://github.com/sponsors/gulien)! ❤️
|
||||||
<img src="https://user-images.githubusercontent.com/8983173/130324668-9d6e7b35-53a3-49c7-a574-38190d2bd6b0.png" alt="TheCodingMachine Logo" width="429" height="210" />
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Badges
|
**Historic & GitHub Sponsors**
|
||||||
|
|
||||||
[](https://hub.docker.com/r/gotenberg/gotenberg)
|
- [TheCodingMachine](https://thecodingmachine.com/)
|
||||||
[](https://hub.docker.com/r/thecodingmachine/gotenberg)
|
- [pdfme](https://pdfme.com/)
|
||||||
[](https://github.com/gotenberg/gotenberg/actions/workflows/continuous_integration.yml)
|
|
||||||
[](https://pkg.go.dev/github.com/gotenberg/gotenberg/v8)
|
**Powered By**
|
||||||
[](https://codecov.io/gh/gotenberg/gotenberg)
|
|
||||||
|
- [Docker](https://docs.docker.com/docker-hub/repos/manage/trusted-content/dsos-program/)
|
||||||
|
- [JetBrains](https://www.jetbrains.com/community/opensource/)
|
||||||
|
|||||||
30
SECURITY.md
30
SECURITY.md
@@ -2,25 +2,25 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Please ensure to keep your environment up-to-date and use only the latest version of Gotenberg.
|
Please ensure to keep your environment up to date and use only the latest version of Gotenberg.
|
||||||
Security updates and patches will be applied only to the most recent version.
|
Security updates and patches will be applied only to the most recent version.
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
Your help in identifying vulnerabilities in our project is much appreciated.
|
Your help in identifying vulnerabilities in our project is much appreciated.
|
||||||
We take all reports regarding security seriously.
|
We take all reports regarding security seriously.
|
||||||
|
|
||||||
If you discover a security vulnerability, please refrain from publishing it publicly.
|
If you discover a security vulnerability, please refrain from publishing it publicly.
|
||||||
Instead, kindly send us the details via email to *neuhart [dot] julien [at] gmail [dot] com*.
|
Instead, kindly send us the details via email to _neuhart [dot] julien [at] gmail [dot] com_.
|
||||||
|
|
||||||
In the subject of your email, please indicate that it's a security vulnerability report for Gotenberg.
|
In the subject of your email, please indicate that it's a security vulnerability report for Gotenberg.
|
||||||
In your message, please include:
|
In your message, please include:
|
||||||
|
|
||||||
* A detailed description of the vulnerability.
|
- A detailed description of the vulnerability.
|
||||||
* The steps to reproduce the issue.
|
- The steps to reproduce the issue.
|
||||||
* Any potential impact of the vulnerability on the users or system.
|
- Any potential impact of the vulnerability on the users or system.
|
||||||
|
|
||||||
Please remember that this process is done in a *'best-effort'* manner.
|
Please remember that this process is done in a _'best-effort'_ manner.
|
||||||
This means we strive to respond and act as quickly as possible, but the speed may vary depending on the severity of
|
This means we strive to respond and act as quickly as possible, but the speed may vary depending on the severity of
|
||||||
the issue and our resources.
|
the issue and our resources.
|
||||||
|
|
||||||
@@ -28,14 +28,14 @@ Thank you in advance for helping to keep our project safe!
|
|||||||
|
|
||||||
## Disclosure Policy
|
## Disclosure Policy
|
||||||
|
|
||||||
Once we have received your vulnerability report, we will work to validate and reproduce the issue.
|
Once we have received your vulnerability report, we will work to validate and reproduce the issue.
|
||||||
If we can confirm the vulnerability, we will proceed to:
|
If we can confirm the vulnerability, we will proceed to:
|
||||||
|
|
||||||
* Work on a fix and a release timeline.
|
- Work on a fix and a release timeline.
|
||||||
* Notify you when the fix has been implemented and released.
|
- Notify you when the fix has been implemented and released.
|
||||||
* Credit you for discovering the vulnerability (unless you request anonymity).
|
- Credit you for discovering the vulnerability (unless you request anonymity).
|
||||||
* Please note that we will do our best to keep you informed about the progress towards resolving the issue.
|
- Please note that we will do our best to keep you informed about the progress towards resolving the issue.
|
||||||
|
|
||||||
## Comments on this Policy
|
## Comments on this Policy
|
||||||
|
|
||||||
If you have suggestions on how this process could be improved, please submit a pull request.
|
If you have suggestions on how this process could be improved, please submit a pull request.
|
||||||
|
|||||||
309
build/Dockerfile
309
build/Dockerfile
@@ -1,15 +1,40 @@
|
|||||||
# ARG instructions do not create additional layers. Instead, next layers will
|
# ARG instructions do not create additional layers. Instead, next layers will
|
||||||
# concatenate them. Also, we have to repeat ARG instructions in each build
|
# concatenate them. Also, we have to repeat ARG instructions in each build
|
||||||
# stage that uses them.
|
# stage that uses them.
|
||||||
ARG GOLANG_VERSION
|
ARG GOLANG_VERSION=1.26.0
|
||||||
|
|
||||||
|
# ----------------------------------------------
|
||||||
|
# pdfcpu binary build stage
|
||||||
|
# ----------------------------------------------
|
||||||
|
# Note: this stage is required as pdfcpu does not release an armhf variant by
|
||||||
|
# default.
|
||||||
|
FROM golang:$GOLANG_VERSION AS pdfcpu-binary-stage
|
||||||
|
|
||||||
|
# See https://github.com/pdfcpu/pdfcpu/releases.
|
||||||
|
ARG PDFCPU_VERSION=v0.11.1
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
|
||||||
|
# Define the working directory outside of $GOPATH (we're using go modules).
|
||||||
|
WORKDIR /home
|
||||||
|
|
||||||
|
RUN curl -Ls "https://github.com/pdfcpu/pdfcpu/archive/refs/tags/$PDFCPU_VERSION.tar.gz" -o pdfcpu.tar.gz &&\
|
||||||
|
tar --strip-components=1 -xvzf pdfcpu.tar.gz
|
||||||
|
|
||||||
|
# Install module dependencies.
|
||||||
|
RUN go mod download &&\
|
||||||
|
go mod verify
|
||||||
|
|
||||||
|
RUN go build -o pdfcpu -ldflags "-s -w -X 'main.version=$PDFCPU_VERSION' -X 'github.com/pdfcpu/pdfcpu/pkg/pdfcpu.VersionStr=$PDFCPU_VERSION' -X main.builtBy=gotenberg" ./cmd/pdfcpu &&\
|
||||||
|
# Verify installation.
|
||||||
|
./pdfcpu version
|
||||||
|
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
# Gotenberg binary build stage
|
# Gotenberg binary build stage
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
FROM golang:$GOLANG_VERSION AS binary-stage
|
FROM golang:$GOLANG_VERSION AS gotenberg-binary-stage
|
||||||
|
|
||||||
ARG GOTENBERG_VERSION
|
ARG GOTENBERG_VERSION=snapshot
|
||||||
ENV CGO_ENABLED 0
|
ENV CGO_ENABLED=0
|
||||||
|
|
||||||
# Define the working directory outside of $GOPATH (we're using go modules).
|
# Define the working directory outside of $GOPATH (we're using go modules).
|
||||||
WORKDIR /home
|
WORKDIR /home
|
||||||
@@ -24,26 +49,83 @@ RUN go mod download &&\
|
|||||||
COPY cmd ./cmd
|
COPY cmd ./cmd
|
||||||
COPY pkg ./pkg
|
COPY pkg ./pkg
|
||||||
|
|
||||||
RUN go build -o gotenberg -ldflags "-X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
|
RUN go build -o gotenberg -ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
|
||||||
|
|
||||||
|
# ----------------------------------------------
|
||||||
|
# Custom JRE stage
|
||||||
|
# Credits: https://github.com/jodconverter/docker-image-jodconverter-runtime
|
||||||
|
# ----------------------------------------------
|
||||||
|
FROM debian:13-slim AS custom-jre-stage
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
apt-get update -qq &&\
|
||||||
|
apt-get upgrade -yqq &&\
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends default-jdk-headless binutils
|
||||||
|
|
||||||
|
# Note: jdeps helps finding which modules a JAR requires.
|
||||||
|
# Currently only for PDFtk, as we don't rely on LibreOffice UNO Java SDK.
|
||||||
|
ENV JAVA_MODULES=java.base,java.desktop,java.xml
|
||||||
|
|
||||||
|
RUN jlink \
|
||||||
|
--add-modules $JAVA_MODULES \
|
||||||
|
--strip-debug \
|
||||||
|
--no-man-pages \
|
||||||
|
--no-header-files \
|
||||||
|
--compress=2 \
|
||||||
|
--output /custom-jre
|
||||||
|
|
||||||
|
# ----------------------------------------------
|
||||||
|
# Downloader stage
|
||||||
|
# ----------------------------------------------
|
||||||
|
FROM debian:13-slim AS downloader-stage
|
||||||
|
|
||||||
|
# See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
|
||||||
|
ARG PDFTK_VERSION=v3.3.3
|
||||||
|
|
||||||
|
RUN apt-get update -qq && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl ca-certificates
|
||||||
|
|
||||||
|
WORKDIR /downloads
|
||||||
|
|
||||||
|
RUN curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.2.0/unoconv -o unoconverter &&\
|
||||||
|
chmod +x unoconverter
|
||||||
|
|
||||||
|
RUN curl -o pdftk-all.jar "https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/$PDFTK_VERSION/pdftk-all.jar" &&\
|
||||||
|
chmod a+x pdftk-all.jar
|
||||||
|
|
||||||
|
# ----------------------------------------------
|
||||||
|
# Base image stage
|
||||||
|
# ----------------------------------------------
|
||||||
|
FROM debian:13-slim AS base-image-stage
|
||||||
|
|
||||||
|
ARG TIMEZONE=UTC
|
||||||
|
ENV TZ=$TIMEZONE
|
||||||
|
# Set default characterset encoding to UTF-8.
|
||||||
|
# See:
|
||||||
|
# https://github.com/gotenberg/gotenberg/issues/104
|
||||||
|
# https://github.com/gotenberg/gotenberg/issues/730
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
COPY --link --from=custom-jre-stage /custom-jre /opt/java
|
||||||
|
|
||||||
|
ENV PATH="/opt/java/bin:${PATH}"
|
||||||
|
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
# Final stage
|
# Final stage
|
||||||
# ----------------------------------------------
|
# ----------------------------------------------
|
||||||
FROM debian:12-slim
|
FROM base-image-stage
|
||||||
|
|
||||||
ARG GOTENBERG_VERSION
|
ARG GOTENBERG_VERSION=snapshot
|
||||||
ARG GOTENBERG_USER_GID
|
ARG GOTENBERG_USER_GID=1001
|
||||||
ARG GOTENBERG_USER_UID
|
ARG GOTENBERG_USER_UID=1001
|
||||||
ARG NOTO_COLOR_EMOJI_VERSION
|
|
||||||
ARG PDFTK_VERSION
|
|
||||||
ARG TMP_CHOMIUM_VERSION_ARMHF="116.0.5845.180-1~deb12u1"
|
|
||||||
|
|
||||||
LABEL org.opencontainers.image.title="Gotenberg" \
|
LABEL org.opencontainers.image.title="Gotenberg" \
|
||||||
org.opencontainers.image.description="A Docker-powered stateless API for PDF files." \
|
org.opencontainers.image.description="A containerized API for seamless PDF conversion." \
|
||||||
org.opencontainers.image.version="$GOTENBERG_VERSION" \
|
org.opencontainers.image.version="$GOTENBERG_VERSION" \
|
||||||
org.opencontainers.image.authors="Julien Neuhart <neuhart.julien@gmail.com>" \
|
org.opencontainers.image.authors="Julien Neuhart <neuhart.julien@gmail.com>" \
|
||||||
org.opencontainers.image.documentation="https://gotenberg.dev" \
|
org.opencontainers.image.documentation="https://gotenberg.dev" \
|
||||||
org.opencontainers.image.source="https://github.com/gotenberg/gotenberg"
|
org.opencontainers.image.source="https://github.com/gotenberg/gotenberg"
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
# Create a non-root user.
|
# Create a non-root user.
|
||||||
@@ -54,147 +136,88 @@ RUN \
|
|||||||
chown gotenberg: /home/gotenberg
|
chown gotenberg: /home/gotenberg
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
# Install system dependencies required for the next instructions or debugging.
|
echo "deb http://deb.debian.org/debian trixie-backports main" >> /etc/apt/sources.list &&\
|
||||||
|
apt-get update -qq &&\
|
||||||
|
apt-get upgrade -yqq &&\
|
||||||
# Note: tini is a helper for reaping zombie processes.
|
# Note: tini is a helper for reaping zombie processes.
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends curl gnupg tini python3 default-jre-headless &&\
|
|
||||||
# Cleanup.
|
|
||||||
# Note: the Debian image does automatically a clean after each install thanks to a hook.
|
|
||||||
# Therefore, there is no need for apt-get clean.
|
|
||||||
# See https://stackoverflow.com/a/24417119/3248473.
|
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
RUN \
|
|
||||||
# Install fonts.
|
|
||||||
# Credits:
|
|
||||||
# https://github.com/arachnys/athenapdf/blob/master/cli/Dockerfile.
|
|
||||||
# https://help.accusoft.com/PrizmDoc/v12.1/HTML/Installing_Asian_Fonts_on_Ubuntu_and_Debian.html.
|
|
||||||
curl -o ./ttf-mscorefonts-installer_3.8.1_all.deb http://httpredir.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8.1_all.deb &&\
|
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
|
||||||
./ttf-mscorefonts-installer_3.8.1_all.deb \
|
tini python3 python3-distutils-extra \
|
||||||
culmus \
|
# Install fonts.
|
||||||
fonts-beng \
|
# Essential metric-compatible fonts for LibreOffice layout fidelity (replaces MS Fonts).
|
||||||
fonts-hosny-amiri \
|
fonts-crosextra-carlito \
|
||||||
fonts-lklug-sinhala \
|
fonts-crosextra-caladea \
|
||||||
fonts-lohit-guru \
|
fonts-liberation \
|
||||||
fonts-lohit-knda \
|
fonts-liberation2 \
|
||||||
fonts-samyak-gujr \
|
# Reliable general-purpose fallback for Chromium.
|
||||||
fonts-samyak-mlym \
|
fonts-dejavu \
|
||||||
fonts-samyak-taml \
|
# Unified CJK (Chinese, Japanese, Korean) support.
|
||||||
fonts-sarai \
|
fonts-noto-cjk \
|
||||||
fonts-sil-abyssinica \
|
# Standard Emoji support.
|
||||||
fonts-sil-padauk \
|
fonts-noto-color-emoji \
|
||||||
fonts-telu \
|
# Install Hyphenation for LibreOffice.
|
||||||
fonts-thai-tlwg \
|
# Credits: https://wiki.archlinux.org/title/LibreOffice.
|
||||||
ttf-wqy-zenhei \
|
hyphen-af hyphen-as hyphen-be hyphen-bg hyphen-bn hyphen-ca hyphen-cs hyphen-da hyphen-de hyphen-el \
|
||||||
fonts-arphic-ukai \
|
hyphen-en-gb hyphen-en-us hyphen-eo hyphen-es hyphen-fr hyphen-gl hyphen-gu hyphen-hi hyphen-hr hyphen-hu \
|
||||||
fonts-arphic-uming \
|
hyphen-id hyphen-is hyphen-it hyphen-kn hyphen-lt hyphen-lv hyphen-ml hyphen-mn hyphen-mr hyphen-nl \
|
||||||
fonts-ipafont-mincho \
|
hyphen-no hyphen-or hyphen-pa hyphen-pl hyphen-pt-br hyphen-pt-pt hyphen-ro hyphen-ru hyphen-sk hyphen-sl \
|
||||||
fonts-ipafont-gothic \
|
hyphen-sr hyphen-sv hyphen-ta hyphen-te hyphen-th hyphen-uk hyphen-zu \
|
||||||
fonts-unfonts-core \
|
# Install Chromium.
|
||||||
# LibreOffice recommends.
|
chromium \
|
||||||
fonts-crosextra-caladea \
|
# Install QPDF & ExifTool (PDF engines).
|
||||||
fonts-crosextra-carlito \
|
qpdf exiftool &&\
|
||||||
fonts-dejavu \
|
|
||||||
fonts-dejavu-extra \
|
|
||||||
fonts-liberation \
|
|
||||||
fonts-liberation2 \
|
|
||||||
fonts-linuxlibertine \
|
|
||||||
fonts-noto-cjk \
|
|
||||||
fonts-noto-core \
|
|
||||||
fonts-noto-mono \
|
|
||||||
fonts-noto-ui-core \
|
|
||||||
fonts-sil-gentium \
|
|
||||||
fonts-sil-gentium-basic &&\
|
|
||||||
rm -f ./ttf-mscorefonts-installer_3.8.1_all.deb &&\
|
|
||||||
# Add Color and Black-and-White Noto emoji font.
|
|
||||||
# Credits:
|
|
||||||
# https://github.com/gotenberg/gotenberg/pull/325.
|
|
||||||
# https://github.com/googlefonts/noto-emoji.
|
|
||||||
curl -Ls "https://github.com/googlefonts/noto-emoji/raw/$NOTO_COLOR_EMOJI_VERSION/fonts/NotoColorEmoji.ttf" -o /usr/local/share/fonts/NotoColorEmoji.ttf &&\
|
|
||||||
# Cleanup.
|
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
RUN \
|
|
||||||
# Install either Google Chrome stable on amd64 architecture or
|
|
||||||
# Chromium on other architectures.
|
|
||||||
# See https://github.com/gotenberg/gotenberg/issues/328.
|
|
||||||
# FIXME:
|
|
||||||
# armhf is currently not working with the latest version of Chromium.
|
|
||||||
# See: https://github.com/gotenberg/gotenberg/issues/709.
|
|
||||||
/bin/bash -c \
|
|
||||||
'set -e &&\
|
|
||||||
if [[ "$(dpkg --print-architecture)" == "amd64" ]]; then \
|
|
||||||
curl https://dl.google.com/linux/linux_signing_key.pub | apt-key add - &&\
|
|
||||||
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list &&\
|
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends --allow-unauthenticated google-chrome-stable &&\
|
|
||||||
mv /usr/bin/google-chrome-stable /usr/bin/chromium; \
|
|
||||||
elif [[ "$(dpkg --print-architecture)" == "armhf" ]]; then \
|
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends devscripts &&\
|
|
||||||
debsnap chromium-common "$TMP_CHOMIUM_VERSION_ARMHF" -v --force --binary --architecture armhf &&\
|
|
||||||
debsnap chromium "$TMP_CHOMIUM_VERSION_ARMHF" -v --force --binary --architecture armhf &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install --fix-broken -y -qq --no-install-recommends "./binary-chromium-common/chromium-common_${TMP_CHOMIUM_VERSION_ARMHF}_armhf.deb" "./binary-chromium/chromium_${TMP_CHOMIUM_VERSION_ARMHF}_armhf.deb" &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get purge -y -qq devscripts &&\
|
|
||||||
rm -rf ./binary-chromium-common/* ./binary-chromium/*; \
|
|
||||||
else \
|
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium; \
|
|
||||||
fi' &&\
|
|
||||||
# Verify installation.
|
|
||||||
chromium --version &&\
|
|
||||||
# Cleanup.
|
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
RUN \
|
|
||||||
# Install LibreOffice & unoconverter.
|
# Install LibreOffice & unoconverter.
|
||||||
echo "deb http://deb.debian.org/debian bookworm-backports main" >> /etc/apt/sources.list &&\
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t trixie-backports \
|
||||||
apt-get update -qq &&\
|
libreoffice-writer libreoffice-calc libreoffice-impress libreoffice-draw python3-uno &&\
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports libreoffice &&\
|
|
||||||
curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.0.1/unoconv -o /usr/bin/unoconverter &&\
|
|
||||||
chmod +x /usr/bin/unoconverter &&\
|
|
||||||
# unoconverter will look for the Python binary, which has to be at version 3.
|
# unoconverter will look for the Python binary, which has to be at version 3.
|
||||||
ln -s /usr/bin/python3 /usr/bin/python &&\
|
ln -s /usr/bin/python3 /usr/bin/python &&\
|
||||||
# Verify installations.
|
|
||||||
libreoffice --version &&\
|
|
||||||
unoconverter --version &&\
|
|
||||||
# Cleanup.
|
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
RUN \
|
|
||||||
# Install PDFtk & QPDF (PDF engines).
|
|
||||||
# See https://github.com/gotenberg/gotenberg/pull/273.
|
|
||||||
curl -o /usr/bin/pdftk-all.jar "https://gitlab.com/api/v4/projects/5024297/packages/generic/pdftk-java/$PDFTK_VERSION/pdftk-all.jar" &&\
|
|
||||||
chmod a+x /usr/bin/pdftk-all.jar &&\
|
|
||||||
echo '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
|
|
||||||
chmod +x /usr/bin/pdftk &&\
|
|
||||||
apt-get update -qq &&\
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends qpdf &&\
|
|
||||||
# See https://github.com/nextcloud/docker/issues/380.
|
# See https://github.com/nextcloud/docker/issues/380.
|
||||||
mkdir -p /usr/share/man/man1 &&\
|
mkdir -p /usr/share/man/man1 &&\
|
||||||
# Verify installations.
|
|
||||||
pdftk --version &&\
|
|
||||||
qpdf --version &&\
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
apt-get autoremove -yqq &&\
|
||||||
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* /usr/share/man/* /usr/share/info/*
|
||||||
|
|
||||||
|
# Copy downloaded artifacts (unoconverter & PDFtk).
|
||||||
|
COPY --link --from=downloader-stage /downloads/unoconverter /usr/bin/unoconverter
|
||||||
|
COPY --link --from=downloader-stage /downloads/pdftk-all.jar /usr/bin/pdftk-all.jar
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
# Install PDFtk bash wrapper.
|
||||||
|
# See https://github.com/gotenberg/gotenberg/pull/273.
|
||||||
|
printf '#!/bin/bash\n\nexec java -jar /usr/bin/pdftk-all.jar "$@"' > /usr/bin/pdftk && \
|
||||||
|
chmod +x /usr/bin/pdftk
|
||||||
|
|
||||||
|
# Support for arbitrary user IDs (OpenShift).
|
||||||
|
# See:
|
||||||
|
# https://github.com/gotenberg/gotenberg/issues/1049.
|
||||||
|
# https://docs.redhat.com/en/documentation/openshift_container_platform/4.15/html/images/creating-images#use-uid_create-images.
|
||||||
|
RUN \
|
||||||
|
usermod -aG root gotenberg &&\
|
||||||
|
chgrp -R 0 /home/gotenberg &&\
|
||||||
|
chmod -R g=u /home/gotenberg
|
||||||
|
|
||||||
# Improve fonts subpixel hinting and smoothing.
|
# Improve fonts subpixel hinting and smoothing.
|
||||||
# Credits:
|
# Credits:
|
||||||
# https://github.com/arachnys/athenapdf/issues/69.
|
# https://github.com/arachnys/athenapdf/issues/69.
|
||||||
# https://github.com/arachnys/athenapdf/commit/ba25a8d80a25d08d58865519c4cd8756dc9a336d.
|
# https://github.com/arachnys/athenapdf/commit/ba25a8d80a25d08d58865519c4cd8756dc9a336d.
|
||||||
COPY build/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf
|
COPY --link build/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf
|
||||||
|
|
||||||
# Copy the Gotenberg binary from the binary stage.
|
# Copy dictionnaries so that hypens work on Chromium.
|
||||||
COPY --from=binary-stage /home/gotenberg /usr/bin/
|
# See https://github.com/gotenberg/gotenberg/issues/1293.
|
||||||
|
COPY --link --chown="$GOTENBERG_USER_UID:$GOTENBERG_USER_GID" build/chromium-hyphen-data /opt/gotenberg/chromium-hyphen-data
|
||||||
|
|
||||||
|
# Copy the Golang binaries.
|
||||||
|
COPY --link --from=pdfcpu-binary-stage /home/pdfcpu /usr/bin/
|
||||||
|
COPY --link --from=gotenberg-binary-stage /home/gotenberg /usr/bin/
|
||||||
|
|
||||||
# Environment variables required by modules or else.
|
# Environment variables required by modules or else.
|
||||||
ENV CHROMIUM_BIN_PATH /usr/bin/chromium
|
ENV CHROMIUM_BIN_PATH=/usr/bin/chromium
|
||||||
ENV LIBREOFFICE_BIN_PATH /usr/lib/libreoffice/program/soffice.bin
|
ENV CHROMIUM_HYPHEN_DATA_DIR_PATH=/opt/gotenberg/chromium-hyphen-data
|
||||||
ENV UNOCONVERTER_BIN_PATH /usr/bin/unoconverter
|
ENV LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin
|
||||||
ENV PDFTK_BIN_PATH /usr/bin/pdftk
|
ENV UNOCONVERTER_BIN_PATH=/usr/bin/unoconverter
|
||||||
ENV QPDF_BIN_PATH /usr/bin/qpdf
|
ENV PDFTK_BIN_PATH=/usr/bin/pdftk
|
||||||
|
ENV QPDF_BIN_PATH=/usr/bin/qpdf
|
||||||
|
ENV EXIFTOOL_BIN_PATH=/usr/bin/exiftool
|
||||||
|
ENV PDFCPU_BIN_PATH=/usr/bin/pdfcpu
|
||||||
|
|
||||||
USER gotenberg
|
USER gotenberg
|
||||||
WORKDIR /home/gotenberg
|
WORKDIR /home/gotenberg
|
||||||
@@ -203,4 +226,4 @@ WORKDIR /home/gotenberg
|
|||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
||||||
CMD [ "gotenberg" ]
|
CMD [ "gotenberg" ]
|
||||||
21
build/Dockerfile.aws-lambda
Normal file
21
build/Dockerfile.aws-lambda
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
ARG DOCKER_REGISTRY
|
||||||
|
ARG DOCKER_REPOSITORY
|
||||||
|
ARG GOTENBERG_VERSION
|
||||||
|
|
||||||
|
FROM $DOCKER_REGISTRY/$DOCKER_REPOSITORY:$GOTENBERG_VERSION
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter
|
||||||
|
|
||||||
|
# AWS.
|
||||||
|
ENV AWS_LWA_PORT=3000
|
||||||
|
ENV AWS_LWA_READINESS_CHECK_PATH=/health
|
||||||
|
ENV AWS_LWA_INVOKE_MODE=buffered
|
||||||
|
|
||||||
|
# Gotenberg.
|
||||||
|
ENV API_PORT_FROM_ENV=AWS_LWA_PORT
|
||||||
|
ENV WEBHOOK_ENABLE_SYNC_MODE=true
|
||||||
|
ENV GOTENBERG_BUILD_DEBUG_DATA=false
|
||||||
|
|
||||||
|
USER gotenberg
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
ARG DOCKER_REGISTRY
|
||||||
ARG DOCKER_REPOSITORY
|
ARG DOCKER_REPOSITORY
|
||||||
ARG GOTENBERG_VERSION
|
ARG GOTENBERG_VERSION
|
||||||
|
|
||||||
FROM $DOCKER_REPOSITORY/gotenberg:$GOTENBERG_VERSION
|
FROM $DOCKER_REGISTRY/$DOCKER_REPOSITORY:$GOTENBERG_VERSION
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
@@ -10,4 +11,12 @@ USER root
|
|||||||
# See https://github.com/gotenberg/gotenberg/issues/90#issuecomment-543551353.
|
# See https://github.com/gotenberg/gotenberg/issues/90#issuecomment-543551353.
|
||||||
RUN chown gotenberg: /usr/bin/tini
|
RUN chown gotenberg: /usr/bin/tini
|
||||||
|
|
||||||
|
# Gotenberg.
|
||||||
|
ENV API_PORT_FROM_ENV=PORT
|
||||||
|
ENV CHROMIUM_AUTO_START=true
|
||||||
|
ENV LIBREOFFICE_AUTO_START=true
|
||||||
|
ENV WEBHOOK_ENABLE_SYNC_MODE=true
|
||||||
|
ENV GOTENBERG_BUILD_DEBUG_DATA=false
|
||||||
|
ENV LOG_ENABLE_GCP_FIELDS=true
|
||||||
|
|
||||||
USER gotenberg
|
USER gotenberg
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-af.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-af.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-as.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-as.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-be.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-be.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-bg.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-bg.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-bn.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-bn.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cs.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cs.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cu.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cu.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cy.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-cy.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-da.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-da.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-1901.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-1901.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-1996.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-1996.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-ch-1901.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-de-ch-1901.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-el.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-el.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-en-gb.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-en-gb.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-en-us.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-en-us.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-es.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-es.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-et.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-et.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-eu.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-eu.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-fr.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-fr.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ga.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ga.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-gl.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-gl.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-gu.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-gu.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hi.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hi.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hr.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hr.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hu.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hu.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hy.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-hy.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-it.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-it.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ka.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ka.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-kn.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-kn.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-la.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-la.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-lt.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-lt.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-lv.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-lv.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ml.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ml.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mn-cyrl.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mn-cyrl.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mr.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mr.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mul-ethi.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-mul-ethi.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nb.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nb.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nl.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nl.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nn.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-nn.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-or.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-or.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-pa.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-pa.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-pt.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-pt.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ru.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ru.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sk.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sk.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sl.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sl.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sq.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sq.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sv.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-sv.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ta.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-ta.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-te.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-te.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-tk.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-tk.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-uk.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-uk.hyb
Normal file
Binary file not shown.
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-und-ethi.hyb
Normal file
BIN
build/chromium-hyphen-data/120.0.6050.0/hyph-und-ethi.hyb
Normal file
Binary file not shown.
5
build/chromium-hyphen-data/120.0.6050.0/manifest.json
Normal file
5
build/chromium-hyphen-data/120.0.6050.0/manifest.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "hyphens-data",
|
||||||
|
"version": "120.0.6050.0"
|
||||||
|
}
|
||||||
105
cmd/gotenberg.go
105
cmd/gotenberg.go
@@ -2,9 +2,11 @@ package gotenbergcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -23,7 +25,7 @@ const banner = `
|
|||||||
\___/\___/\__/\__/_//_/_.__/\__/_/ \_, /
|
\___/\___/\__/\__/_//_/_.__/\__/_/ \_, /
|
||||||
/___/
|
/___/
|
||||||
|
|
||||||
A Docker-powered stateless API for PDF files.
|
A containerized API for seamless PDF conversion.
|
||||||
Version: %s
|
Version: %s
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
`
|
`
|
||||||
@@ -34,37 +36,102 @@ var Version = "snapshot"
|
|||||||
|
|
||||||
// Run starts the Gotenberg application. Call this in the main of your program.
|
// Run starts the Gotenberg application. Call this in the main of your program.
|
||||||
func Run() {
|
func Run() {
|
||||||
fmt.Printf(banner, Version)
|
gotenberg.Version = Version
|
||||||
|
|
||||||
// Create the root FlagSet and adds the modules flags to it.
|
// Create the root FlagSet and adds the modules flags to it.
|
||||||
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
|
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
|
||||||
|
fs.Bool("gotenberg-hide-banner", false, "Hide the banner")
|
||||||
fs.Duration("gotenberg-graceful-shutdown-duration", time.Duration(30)*time.Second, "Set the graceful shutdown duration")
|
fs.Duration("gotenberg-graceful-shutdown-duration", time.Duration(30)*time.Second, "Set the graceful shutdown duration")
|
||||||
|
fs.Bool("gotenberg-build-debug-data", true, "Set if build data is needed")
|
||||||
|
fs.String("log-level", gotenberg.InfoLoggingLevel, fmt.Sprintf("Choose the level of logging detail. Options include %s, %s, %s, or %s", gotenberg.ErrorLoggingLevel, gotenberg.WarnLoggingLevel, gotenberg.InfoLoggingLevel, gotenberg.DebugLoggingLevel))
|
||||||
|
fs.String("log-fields-prefix", "", "Prepend a specified prefix to each field in the logs")
|
||||||
|
fs.String("log-std-format", gotenberg.AutoLoggingFormat, fmt.Sprintf("Specify the format of standard logging. Options include %s, %s, or %s", gotenberg.AutoLoggingFormat, gotenberg.JsonLoggingFormat, gotenberg.TextLoggingFormat))
|
||||||
|
fs.Bool("log-std-enable-gcp-fields", false, "Enable Google Cloud Platform fields for standard logging - namely: time, message, severity")
|
||||||
|
|
||||||
descriptors := gotenberg.GetModuleDescriptors()
|
descriptors := gotenberg.GetModuleDescriptors()
|
||||||
var modsInfo string
|
var modsInfo strings.Builder
|
||||||
for _, desc := range descriptors {
|
for _, desc := range descriptors {
|
||||||
fs.AddFlagSet(desc.FlagSet)
|
fs.AddFlagSet(desc.FlagSet)
|
||||||
modsInfo += desc.ID + " "
|
modsInfo.WriteString(desc.ID + " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo)
|
// Parse the flags.
|
||||||
|
|
||||||
// Parse the flags...
|
|
||||||
err := fs.Parse(os.Args[1:])
|
err := fs.Parse(os.Args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...and create a wrapper around those.
|
// Override their values if the corresponding environment variables are
|
||||||
parsedFlags := gotenberg.ParsedFlags{FlagSet: fs}
|
// set.
|
||||||
|
fs.VisitAll(func(f *flag.Flag) {
|
||||||
|
envName := strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_"))
|
||||||
|
val, ok := os.LookupEnv(envName)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get the graceful shutdown duration.
|
sliceVal, ok := f.Value.(flag.SliceValue)
|
||||||
|
if ok {
|
||||||
|
// We don't want to append the values (default pflag behavior).
|
||||||
|
items := strings.Split(val, ",")
|
||||||
|
err = sliceVal.Replace(items)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[FATAL] invalid overriding value '%s' from %s: %v\n", val, envName, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f.Value.Set(val)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[FATAL] invalid overriding value '%s' from %s: %v\n", val, envName, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a wrapper around our flags.
|
||||||
|
parsedFlags := gotenberg.ParsedFlags{FlagSet: fs}
|
||||||
|
hideBanner := parsedFlags.MustBool("gotenberg-hide-banner")
|
||||||
gracefulShutdownDuration := parsedFlags.MustDuration("gotenberg-graceful-shutdown-duration")
|
gracefulShutdownDuration := parsedFlags.MustDuration("gotenberg-graceful-shutdown-duration")
|
||||||
|
|
||||||
|
serviceName := os.Getenv("OTEL_SERVICE_NAME")
|
||||||
|
if serviceName == "" {
|
||||||
|
serviceName = "gotenberg"
|
||||||
|
}
|
||||||
|
|
||||||
|
telemetryConfig := gotenberg.TelemetryConfig{
|
||||||
|
// OpenTelemetry.
|
||||||
|
ServiceName: serviceName,
|
||||||
|
ServiceVersion: Version,
|
||||||
|
// Logging.
|
||||||
|
LogLevel: parsedFlags.MustString("log-level"),
|
||||||
|
LogFieldsPrefix: parsedFlags.MustString("log-fields-prefix"),
|
||||||
|
LogStdFormat: parsedFlags.MustDeprecatedString("log-format", "log-std-format"),
|
||||||
|
LogStdEnableGcpFields: parsedFlags.MustDeprecatedBool("log-enable-gcp-fields", "log-std-enable-gcp-fields"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hideBanner {
|
||||||
|
fmt.Printf(banner, Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = telemetryConfig.Validate()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[FATAL] telemetry: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Telemetry.
|
||||||
|
shutdownTelemetry, err := gotenberg.StartTelemetry(telemetryConfig)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[FATAL] telemetry: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modules.
|
||||||
|
fmt.Printf("[SYSTEM] modules: %s\n", modsInfo.String())
|
||||||
ctx := gotenberg.NewContext(parsedFlags, descriptors)
|
ctx := gotenberg.NewContext(parsedFlags, descriptors)
|
||||||
|
|
||||||
// Start application modules.
|
|
||||||
apps, err := ctx.Modules(new(gotenberg.App))
|
apps, err := ctx.Modules(new(gotenberg.App))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[FATAL] %s\n", err)
|
fmt.Printf("[FATAL] %s\n", err)
|
||||||
@@ -107,6 +174,11 @@ func Run() {
|
|||||||
}(l.(gotenberg.SystemLogger))
|
}(l.(gotenberg.SystemLogger))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if parsedFlags.MustBool("gotenberg-build-debug-data") {
|
||||||
|
// Build the debug data.
|
||||||
|
gotenberg.BuildDebug(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
|
|
||||||
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) or SIGTERM (Kubernetes).
|
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) or SIGTERM (Kubernetes).
|
||||||
@@ -137,7 +209,9 @@ func Run() {
|
|||||||
id := app.(gotenberg.Module).Descriptor().ID
|
id := app.(gotenberg.Module).Descriptor().ID
|
||||||
|
|
||||||
err = app.Stop(gracefulShutdownCtx)
|
err = app.Stop(gracefulShutdownCtx)
|
||||||
if err != nil {
|
if errors.Is(err, gotenberg.ErrCancelGracefulShutdownContext) {
|
||||||
|
cancel()
|
||||||
|
} else if err != nil {
|
||||||
return fmt.Errorf("stopping %s: %w", id, err)
|
return fmt.Errorf("stopping %s: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,5 +227,12 @@ func Run() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = shutdownTelemetry(gracefulShutdownCtx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("[FATAL] telemetry: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("[SYSTEM] telemetry: shutdown success\n")
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
103
compose.yaml
Normal file
103
compose.yaml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
services:
|
||||||
|
gotenberg:
|
||||||
|
image: ${DOCKER_REGISTRY}/${DOCKER_REPOSITORY}:${GOTENBERG_VERSION}
|
||||||
|
ports:
|
||||||
|
- "${API_PORT}:${API_PORT}"
|
||||||
|
environment:
|
||||||
|
GOTENBERG_API_BASIC_AUTH_USERNAME: ${GOTENBERG_API_BASIC_AUTH_USERNAME}
|
||||||
|
GOTENBERG_API_BASIC_AUTH_PASSWORD: ${GOTENBERG_API_BASIC_AUTH_PASSWORD}
|
||||||
|
OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME}
|
||||||
|
OTEL_TRACES_EXPORTER: ${OTEL_TRACES_EXPORTER}
|
||||||
|
OTEL_METRICS_EXPORTER: ${OTEL_METRICS_EXPORTER}
|
||||||
|
OTEL_LOGS_EXPORTER: ${OTEL_LOGS_EXPORTER}
|
||||||
|
OTEL_EXPORTER_OTLP_PROTOCOL: ${OTEL_EXPORTER_OTLP_PROTOCOL}
|
||||||
|
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT}
|
||||||
|
OTEL_EXPORTER_OTLP_INSECURE: ${OTEL_EXPORTER_OTLP_INSECURE}
|
||||||
|
command:
|
||||||
|
- "gotenberg"
|
||||||
|
- "--gotenberg-hide-banner=${GOTENBERG_HIDE_BANNER}"
|
||||||
|
- "--gotenberg-graceful-shutdown-duration=${GOTENBERG_GRACEFUL_SHUTDOWN_DURATION}"
|
||||||
|
- "--gotenberg-build-debug-data=${GOTENBERG_BUILD_DEBUG_DATA}"
|
||||||
|
- "--api-port=${API_PORT}"
|
||||||
|
- "--api-port-from-env=${API_PORT_FROM_ENV}"
|
||||||
|
- "--api-bind-ip=${API_BIND_IP}"
|
||||||
|
- "--api-start-timeout=${API_START_TIMEOUT}"
|
||||||
|
- "--api-timeout=${API_TIMEOUT}"
|
||||||
|
- "--api-body-limit=${API_BODY_LIMIT}"
|
||||||
|
- "--api-root-path=${API_ROOT_PATH}"
|
||||||
|
- "--api-correlation-id-header=${API_CORRELATION_ID_HEADER}"
|
||||||
|
- "--api-enable-basic-auth=${API_ENABLE_BASIC_AUTH}"
|
||||||
|
- "--api-download-from-allow-list=${API_DOWNLOAD_FROM_ALLOW_LIST}"
|
||||||
|
- "--api-download-from-deny-list=${API_DOWNLOAD_FROM_DENY_LIST}"
|
||||||
|
- "--api-download-from-max-retry=${API_DOWNLOAD_FROM_MAX_RETRY}"
|
||||||
|
- "--api-disable-download-from=${API_DISABLE_DOWNLOAD_FROM}"
|
||||||
|
- "--api-disable-health-check-route-telemetry=${API_DISABLE_HEALTH_CHECK_ROUTE_TELEMETRY}"
|
||||||
|
- "--api-disable-root-route-telemetry=${API_DISABLE_ROOT_ROUTE_TELEMETRY}"
|
||||||
|
- "--api-disable-version-route-telemetry=${API_DISABLE_VERSION_ROUTE_TELEMETRY}"
|
||||||
|
- "--api-disable-debug-route-telemetry=${API_DISABLE_DEBUG_ROUTE_TELEMETRY}"
|
||||||
|
- "--api-enable-debug-route=${API_ENABLE_DEBUG_ROUTE}"
|
||||||
|
- "--chromium-restart-after=${CHROMIUM_RESTART_AFTER}"
|
||||||
|
- "--chromium-auto-start=${CHROMIUM_AUTO_START}"
|
||||||
|
- "--chromium-max-queue-size=${CHROMIUM_MAX_QUEUE_SIZE}"
|
||||||
|
- "--chromium-max-concurrency=${CHROMIUM_MAX_CONCURRENCY}"
|
||||||
|
- "--chromium-start-timeout=${CHROMIUM_START_TIMEOUT}"
|
||||||
|
- "--chromium-allow-insecure-localhost=${CHROMIUM_ALLOW_INSECURE_LOCALHOST}"
|
||||||
|
- "--chromium-ignore-certificate-errors=${CHROMIUM_IGNORE_CERTIFICATE_ERRORS}"
|
||||||
|
- "--chromium-disable-web-security=${CHROMIUM_DISABLE_WEB_SECURITY}"
|
||||||
|
- "--chromium-allow-file-access-from-files=${CHROMIUM_ALLOW_FILE_ACCESS_FROM_FILES}"
|
||||||
|
- "--chromium-host-resolver-rules=${CHROMIUM_HOST_RESOLVER_RULES}"
|
||||||
|
- "--chromium-proxy-server=${CHROMIUM_PROXY_SERVER}"
|
||||||
|
- "--chromium-allow-list=${CHROMIUM_ALLOW_LIST}"
|
||||||
|
- "--chromium-deny-list=${CHROMIUM_DENY_LIST}"
|
||||||
|
- "--chromium-clear-cache=${CHROMIUM_CLEAR_CACHE}"
|
||||||
|
- "--chromium-clear-cookies=${CHROMIUM_CLEAR_COOKIES}"
|
||||||
|
- "--chromium-disable-javascript=${CHROMIUM_DISABLE_JAVASCRIPT}"
|
||||||
|
- "--chromium-disable-routes=${CHROMIUM_DISABLE_ROUTES}"
|
||||||
|
- "--libreoffice-restart-after=${LIBREOFFICE_RESTART_AFTER}"
|
||||||
|
- "--libreoffice-max-queue-size=${LIBREOFFICE_MAX_QUEUE_SIZE}"
|
||||||
|
- "--libreoffice-auto-start=${LIBREOFFICE_AUTO_START}"
|
||||||
|
- "--libreoffice-start-timeout=${LIBREOFFICE_START_TIMEOUT}"
|
||||||
|
- "--libreoffice-disable-routes=${LIBREOFFICE_DISABLE_ROUTES}"
|
||||||
|
- "--log-level=${LOG_LEVEL}"
|
||||||
|
- "--log-fields-prefix=${LOG_FIELDS_PREFIX}"
|
||||||
|
- "--log-std-format=${LOG_STD_FORMAT}"
|
||||||
|
- "--log-std-enable-gcp-fields=${LOG_STD_ENABLE_GCP_FIELDS}"
|
||||||
|
- "--pdfengines-merge-engines=${PDFENGINES_MERGE_ENGINES}"
|
||||||
|
- "--pdfengines-split-engines=${PDFENGINES_SPLIT_ENGINES}"
|
||||||
|
- "--pdfengines-flatten-engines=${PDFENGINES_FLATTEN_ENGINES}"
|
||||||
|
- "--pdfengines-convert-engines=${PDFENGINES_CONVERT_ENGINES}"
|
||||||
|
- "--pdfengines-read-metadata-engines=${PDFENGINES_READ_METADATA_ENGINES}"
|
||||||
|
- "--pdfengines-write-metadata-engines=${PDFENGINES_WRITE_METADATA_ENGINES}"
|
||||||
|
- "--pdfengines-encrypt-engines=${PDFENGINES_ENCRYPT_ENGINES}"
|
||||||
|
- "--pdfengines-disable-routes=${PDFENGINES_DISABLE_ROUTES}"
|
||||||
|
- "--pdfengines-add-attachments-engines=${PDFENGINES_ADD_ATTACHMENTS_ENGINES}"
|
||||||
|
- "--webhook-enable-sync-mode=${WEBHOOK_ENABLE_SYNC_MODE}"
|
||||||
|
- "--webhook-allow-list=${WEBHOOK_ALLOW_LIST}"
|
||||||
|
- "--webhook-deny-list=${WEBHOOK_DENY_LIST}"
|
||||||
|
- "--webhook-error-allow-list=${WEBHOOK_ERROR_ALLOW_LIST}"
|
||||||
|
- "--webhook-error-deny-list=${WEBHOOK_ERROR_DENY_LIST}"
|
||||||
|
- "--webhook-max-retry=${WEBHOOK_MAX_RETRY}"
|
||||||
|
- "--webhook-retry-min-wait=${WEBHOOK_RETRY_MIN_WAIT}"
|
||||||
|
- "--webhook-retry-max-wait=${WEBHOOK_RETRY_MAX_WAIT}"
|
||||||
|
- "--webhook-client-timeout=${WEBHOOK_CLIENT_TIMEOUT}"
|
||||||
|
- "--webhook-disable=${WEBHOOK_DISABLE}"
|
||||||
|
|
||||||
|
otel-collector:
|
||||||
|
image: otel/opentelemetry-collector-contrib:latest
|
||||||
|
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||||
|
volumes:
|
||||||
|
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||||
|
ports:
|
||||||
|
- "4317:4317" # OTLP gRPC receiver
|
||||||
|
depends_on:
|
||||||
|
- openobserve
|
||||||
|
|
||||||
|
openobserve:
|
||||||
|
image: public.ecr.aws/zinclabs/openobserve:latest
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "5080:5080"
|
||||||
|
- "5081:5081" # OTLP gRPC ingestion
|
||||||
|
environment:
|
||||||
|
ZO_ROOT_USER_EMAIL: telemetry@gotenberg.dev
|
||||||
|
ZO_ROOT_USER_PASSWORD: telemetry
|
||||||
176
go.mod
176
go.mod
@@ -1,67 +1,147 @@
|
|||||||
module github.com/gotenberg/gotenberg/v8
|
module github.com/gotenberg/gotenberg/v8
|
||||||
|
|
||||||
go 1.21
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alexliesenfeld/health v0.8.0
|
github.com/alexliesenfeld/health v0.8.1
|
||||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
github.com/barasher/go-exiftool v1.10.0
|
||||||
github.com/chromedp/cdproto v0.0.0-20240214232516-ad4608604e9e
|
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d
|
||||||
github.com/chromedp/chromedp v0.9.5
|
github.com/chromedp/chromedp v0.14.2
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/cucumber/godog v0.15.1
|
||||||
|
github.com/dlclark/regexp2 v1.11.5
|
||||||
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
|
github.com/docker/go-connections v0.6.0
|
||||||
|
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.8
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.5
|
github.com/labstack/echo/v4 v4.15.1
|
||||||
github.com/klauspost/compress v1.17.6 // indirect
|
|
||||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
|
||||||
github.com/labstack/echo/v4 v4.11.4
|
|
||||||
github.com/labstack/gommon v0.4.2
|
github.com/labstack/gommon v0.4.2
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mholt/archives v0.1.5
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26
|
github.com/shirou/gopsutil/v4 v4.26.1
|
||||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
github.com/spf13/pflag v1.0.10
|
||||||
github.com/pdfcpu/pdfcpu v0.6.0
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
github.com/prometheus/client_golang v1.18.0
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0
|
||||||
github.com/russross/blackfriday/v2 v2.1.0
|
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0
|
||||||
github.com/spf13/pflag v1.0.5
|
go.opentelemetry.io/otel v1.42.0
|
||||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
go.opentelemetry.io/otel/log v0.18.0
|
||||||
|
go.opentelemetry.io/otel/metric v1.42.0
|
||||||
|
go.opentelemetry.io/otel/sdk v1.42.0
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.18.0
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.42.0
|
||||||
|
go.opentelemetry.io/otel/trace v1.42.0
|
||||||
go.uber.org/multierr v1.11.0
|
go.uber.org/multierr v1.11.0
|
||||||
go.uber.org/zap v1.26.0
|
golang.org/x/net v0.51.0
|
||||||
golang.org/x/crypto v0.19.0 // indirect
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/image v0.15.0 // indirect
|
golang.org/x/term v0.40.0
|
||||||
golang.org/x/net v0.21.0
|
golang.org/x/text v0.34.0
|
||||||
golang.org/x/sync v0.6.0
|
|
||||||
golang.org/x/sys v0.17.0 // indirect
|
|
||||||
golang.org/x/term v0.17.0
|
|
||||||
golang.org/x/text v0.14.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/dlclark/regexp2 v1.10.0
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
|
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||||
|
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
github.com/bodgit/windows v1.0.1 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||||
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||||
|
github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect
|
||||||
|
github.com/cucumber/messages/go/v21 v21.0.1 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||||
|
github.com/ebitengine/purego v0.10.0 // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
github.com/gobwas/httphead v0.1.0 // indirect
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
github.com/gobwas/pool v0.2.1 // indirect
|
||||||
github.com/gobwas/ws v1.3.2 // indirect
|
github.com/gobwas/ws v1.4.0 // indirect
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/hhrutter/lzw v1.0.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||||
github.com/hhrutter/tiff v1.0.1 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/hashicorp/go-memdb v1.3.5 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
|
github.com/klauspost/compress v1.18.4 // indirect
|
||||||
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||||
|
github.com/minio/minlz v1.0.1 // indirect
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/go-archive v0.2.0 // indirect
|
||||||
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
|
github.com/moby/term v0.5.2 // indirect
|
||||||
|
github.com/morikuni/aec v1.1.0 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/nwaples/rardecode/v2 v2.2.2 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.25 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_model v0.6.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/common v0.47.0 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
|
github.com/prometheus/common v0.67.5 // indirect
|
||||||
|
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.20.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||||
|
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||||
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||||
|
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
|
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
|
||||||
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
|
golang.org/x/sys v0.41.0 // indirect
|
||||||
|
golang.org/x/time v0.14.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
|
google.golang.org/grpc v1.79.2 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
412
go.sum
412
go.sum
@@ -1,163 +1,359 @@
|
|||||||
github.com/alexliesenfeld/health v0.8.0 h1:lCV0i+ZJPTbqP7LfKG7p3qZBl5VhelwUFCIVWl77fgk=
|
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||||
github.com/alexliesenfeld/health v0.8.0/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
|
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
|
github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=
|
||||||
|
github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=
|
||||||
|
github.com/alexliesenfeld/health v0.8.1 h1:wdE3vt+cbJotiR8DGDBZPKHDFoJbAoWEfQTcqrmedUg=
|
||||||
|
github.com/alexliesenfeld/health v0.8.1/go.mod h1:TfNP0f+9WQVWMQRzvMUjlws4ceXKEL3WR+6Hp95HUFc=
|
||||||
|
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||||
|
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
|
github.com/barasher/go-exiftool v1.10.0 h1:f5JY5jc42M7tzR6tbL9508S2IXdIcG9QyieEXNMpIhs=
|
||||||
|
github.com/barasher/go-exiftool v1.10.0/go.mod h1:F9s/a3uHSM8YniVfwF+sbQUtP8Gmh9nyzigNF+8vsWo=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||||
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
|
||||||
github.com/chromedp/cdproto v0.0.0-20240214232516-ad4608604e9e h1:kXEolCWQZzuEFcuaTzfqXToX+e29OcvK87BcBiBBJ1c=
|
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
|
||||||
github.com/chromedp/cdproto v0.0.0-20240214232516-ad4608604e9e/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||||
github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg=
|
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||||
github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||||
|
github.com/chromedp/chromedp v0.14.2 h1:r3b/WtwM50RsBZHMUm9fsNhhzRStTHrKdr2zmwbZSzM=
|
||||||
|
github.com/chromedp/chromedp v0.14.2/go.mod h1:rHzAv60xDE7VNy/MYtTUrYreSc0ujt2O1/C3bzctYBo=
|
||||||
|
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||||
|
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||||
|
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||||
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
|
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||||
|
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
|
github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI=
|
||||||
|
github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0=
|
||||||
|
github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI=
|
||||||
|
github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8=
|
||||||
|
github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI=
|
||||||
|
github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s=
|
||||||
|
github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
|
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
|
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
|
||||||
|
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 h1:vymEbVwYFP/L05h5TKQxvkXoKxNvTpjxYKdF1Nlwuao=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=
|
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||||
github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=
|
||||||
|
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
|
github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
|
||||||
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
|
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
|
github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
|
||||||
github.com/hhrutter/tiff v1.0.1 h1:MIus8caHU5U6823gx7C6jrfoEvfSTGtEFRiM8/LOzC0=
|
github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo=
|
||||||
github.com/hhrutter/tiff v1.0.1/go.mod h1:zU/dNgDm0cMIa8y8YwcYBeuEEveI4B0owqHyiPpJPHc=
|
github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||||
|
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
|
||||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/labstack/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs=
|
||||||
|
github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
||||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4=
|
||||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=
|
||||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=
|
||||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=
|
||||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
|
||||||
|
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
|
||||||
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
|
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||||
|
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
|
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
|
||||||
|
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/nwaples/rardecode/v2 v2.2.2 h1:/5oL8dzYivRM/tqX9VcTSWfbpwcbwKG1QtSJr3b3KcU=
|
||||||
|
github.com/nwaples/rardecode/v2 v2.2.2/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||||
github.com/pdfcpu/pdfcpu v0.6.0 h1:z4kARP5bcWa39TTYMcN/kjBnm7MvhTWjXgeYmkdAGMI=
|
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
|
||||||
github.com/pdfcpu/pdfcpu v0.6.0/go.mod h1:kmpD0rk8YnZj0l3qSeGBlAB+XszHUgNv//ORH/E7EYo=
|
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
|
||||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k=
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo=
|
||||||
|
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
|
||||||
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=
|
||||||
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
|
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||||
|
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||||
|
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0 h1:yOYhGNPZseueTTvWp5iBD3/CthrmvayUXYEX862dDi4=
|
||||||
|
go.opentelemetry.io/contrib/bridges/otelslog v0.15.0/go.mod h1:CvaNVqIfcybc+7xqZNubbE+26K6P7AKZF/l0lE2kdCk=
|
||||||
|
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXvpd09vxvDZsOjx11gjUqLk=
|
||||||
|
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0/go.mod h1:Z5RIwRkZgauOIfnG5IpidvLpERjhTninpP1dTG2jTl4=
|
||||||
|
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9achKn3XgmxPxuMuqIL5rE8e8=
|
||||||
|
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||||
|
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||||
|
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 h1:H7O6RlGOMTizyl3R08Kn5pdM06bnH8oscSj7o11tmLA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0/go.mod h1:mBFWu/WOVDkWWsR7Tx7h6EpQB8wsv7P0Yrh0Pb7othc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 h1:KJVjPD3rcPb98rIs3HznyJlrfx9ge5oJvxxlGR+P/7s=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0/go.mod h1:K3kRa2ckmHWQaTWQdPRHc7qGXASuVuoEQXzrvlA98Ws=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 h1:lSZHgNHfbmQTPfuTmWVkEu8J8qXaQwuV30pjCcAUvP8=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0/go.mod h1:so9ounLcuoRDu033MW/E0AD4hhUjVqswrMF5FoZlBcw=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
|
||||||
|
go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg=
|
||||||
|
go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI=
|
||||||
|
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||||
|
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk=
|
||||||
|
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA=
|
||||||
|
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
|
||||||
|
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||||
|
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
go4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
go4.org v0.0.0-20260112195520-a5071408f32f/go.mod h1:ZRJnO5ZI4zAwMFp+dS1+V6J6MSyAowhRqAE+DPa1Xp0=
|
||||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
|
|||||||
32
otel-collector-config.yaml
Normal file
32
otel-collector-config.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
grpc:
|
||||||
|
endpoint: "0.0.0.0:4317"
|
||||||
|
|
||||||
|
processors:
|
||||||
|
batch:
|
||||||
|
|
||||||
|
exporters:
|
||||||
|
otlp/openobserve:
|
||||||
|
endpoint: "openobserve:5081"
|
||||||
|
tls:
|
||||||
|
insecure: true
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic dGVsZW1ldHJ5QGdvdGVuYmVyZy5kZXY6dGVsZW1ldHJ5"
|
||||||
|
organization: "default"
|
||||||
|
|
||||||
|
service:
|
||||||
|
pipelines:
|
||||||
|
traces:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [otlp/openobserve]
|
||||||
|
metrics:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [otlp/openobserve]
|
||||||
|
logs:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [otlp/openobserve]
|
||||||
153
package-lock.json
generated
Normal file
153
package-lock.json
generated
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
{
|
||||||
|
"name": "gotenberg",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.8.1",
|
||||||
|
"prettier-plugin-gherkin": "^3.1.3",
|
||||||
|
"prettier-plugin-sh": "^0.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cucumber/gherkin": {
|
||||||
|
"version": "32.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-32.2.0.tgz",
|
||||||
|
"integrity": "sha512-X8xuVhSIqlUjxSRifRJ7t0TycVWyX58fygJH3wDNmHINLg9sYEkvQT0SO2G5YlRZnYc11TIFr4YPenscvdlBIw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cucumber/messages": ">=19.1.4 <28"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cucumber/messages": {
|
||||||
|
"version": "27.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-27.2.0.tgz",
|
||||||
|
"integrity": "sha512-f2o/HqKHgsqzFLdq6fAhfG1FNOQPdBdyMGpKwhb7hZqg0yZtx9BVqkTyuoNk83Fcvk3wjMVfouFXXHNEk4nddA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/uuid": "10.0.0",
|
||||||
|
"class-transformer": "0.5.1",
|
||||||
|
"reflect-metadata": "0.2.2",
|
||||||
|
"uuid": "11.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@reteps/dockerfmt": {
|
||||||
|
"version": "0.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@reteps/dockerfmt/-/dockerfmt-0.3.6.tgz",
|
||||||
|
"integrity": "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^v12.20.0 || ^14.13.0 || >=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/uuid": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/class-transformer": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
|
||||||
|
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||||
|
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-plugin-gherkin": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-gherkin/-/prettier-plugin-gherkin-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-w9uB413NlSi8ZQwpexyu+ttriJJ88eZLV0x88ZTkzkLZyHYEX5wrNtaCx/yFYviIu/tuwsBqDPM47VODnIV/hw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cucumber/gherkin": "^32.0.0",
|
||||||
|
"@cucumber/messages": "^27.2.0",
|
||||||
|
"prettier": "^3.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-plugin-sh": {
|
||||||
|
"version": "0.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.18.0.tgz",
|
||||||
|
"integrity": "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@reteps/dockerfmt": "^0.3.6",
|
||||||
|
"sh-syntax": "^0.5.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/unts"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": "^3.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/reflect-metadata": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/sh-syntax": {
|
||||||
|
"version": "0.5.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.5.8.tgz",
|
||||||
|
"integrity": "sha512-JfVoxf4FxQI5qpsPbkHhZo+n6N9YMJobyl4oGEUBb/31oQYlgTjkXQD8PBiafS2UbWoxrTO0Z5PJUBXEPAG1Zw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/sh-syntax"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "11.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz",
|
||||||
|
"integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/esm/bin/uuid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
package.json
Normal file
7
package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.8.1",
|
||||||
|
"prettier-plugin-gherkin": "^3.1.3",
|
||||||
|
"prettier-plugin-sh": "^0.18.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,17 +6,16 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cmd wraps an [exec.Cmd].
|
// Cmd wraps an [exec.Cmd].
|
||||||
type Cmd struct {
|
type Cmd struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
logger *zap.Logger
|
logger *slog.Logger
|
||||||
process *exec.Cmd
|
process *exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,13 +24,13 @@ type Cmd struct {
|
|||||||
// children without creating orphans.
|
// children without creating orphans.
|
||||||
//
|
//
|
||||||
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
|
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
|
||||||
func Command(logger *zap.Logger, binPath string, args ...string) *Cmd {
|
func Command(logger *slog.Logger, binPath string, args ...string) *Cmd {
|
||||||
cmd := exec.Command(binPath, args...)
|
cmd := exec.Command(binPath, args...)
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
|
||||||
return &Cmd{
|
return &Cmd{
|
||||||
ctx: nil,
|
ctx: nil,
|
||||||
logger: logger.Named(strings.ReplaceAll(binPath, "/", "")),
|
logger: logger.With(slog.String("logger", strings.ReplaceAll(binPath, "/", ""))),
|
||||||
process: cmd,
|
process: cmd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +40,7 @@ func Command(logger *zap.Logger, binPath string, args ...string) *Cmd {
|
|||||||
// children without creating orphans.
|
// children without creating orphans.
|
||||||
//
|
//
|
||||||
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
|
// See https://medium.com/@felixge/killing-a-child-process-and-all-of-its-children-in-go-54079af94773.
|
||||||
func CommandContext(ctx context.Context, logger *zap.Logger, binPath string, args ...string) (*Cmd, error) {
|
func CommandContext(ctx context.Context, logger *slog.Logger, binPath string, args ...string) (*Cmd, error) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return nil, errors.New("nil context")
|
return nil, errors.New("nil context")
|
||||||
}
|
}
|
||||||
@@ -51,7 +50,7 @@ func CommandContext(ctx context.Context, logger *zap.Logger, binPath string, arg
|
|||||||
|
|
||||||
return &Cmd{
|
return &Cmd{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
logger: logger.Named(strings.ReplaceAll(binPath, "/", "")),
|
logger: logger.With(slog.String("logger", strings.ReplaceAll(binPath, "/", ""))),
|
||||||
process: cmd,
|
process: cmd,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -63,7 +62,7 @@ func (cmd *Cmd) Start() error {
|
|||||||
return fmt.Errorf("pipe unix process output: %w", err)
|
return fmt.Errorf("pipe unix process output: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.logger.Debug(fmt.Sprintf("start unix process: %s", strings.Join(cmd.process.Args, " ")))
|
cmd.logger.DebugContext(cmd.ctx, fmt.Sprintf("start unix process: %s", strings.Join(cmd.process.Args, " ")))
|
||||||
|
|
||||||
err = cmd.process.Start()
|
err = cmd.process.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -74,7 +73,7 @@ func (cmd *Cmd) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait waits for the command to complete. It should be called when using the
|
// Wait waits for the command to complete. It should be called when using the
|
||||||
// Start method, so that the command does not leak zombies.
|
// Start method so that the command does not leak zombies.
|
||||||
func (cmd *Cmd) Wait() error {
|
func (cmd *Cmd) Wait() error {
|
||||||
err := cmd.process.Wait()
|
err := cmd.process.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,7 +83,7 @@ func (cmd *Cmd) Wait() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the command and wait for its completion or until the context
|
// Exec executes the command and waits for its completion or until the context
|
||||||
// is done. In any case, it kills the unix process and all its children.
|
// is done. In any case, it kills the unix process and all its children.
|
||||||
func (cmd *Cmd) Exec() (int, error) {
|
func (cmd *Cmd) Exec() (int, error) {
|
||||||
if cmd.ctx == nil {
|
if cmd.ctx == nil {
|
||||||
@@ -110,7 +109,7 @@ func (cmd *Cmd) Exec() (int, error) {
|
|||||||
case err = <-errChan:
|
case err = <-errChan:
|
||||||
errProc := cmd.Kill()
|
errProc := cmd.Kill()
|
||||||
if errProc != nil {
|
if errProc != nil {
|
||||||
cmd.logger.Error(errProc.Error())
|
cmd.logger.ErrorContext(cmd.ctx, errProc.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -125,7 +124,7 @@ func (cmd *Cmd) Exec() (int, error) {
|
|||||||
case <-cmd.ctx.Done():
|
case <-cmd.ctx.Done():
|
||||||
errProc := cmd.Kill()
|
errProc := cmd.Kill()
|
||||||
if errProc != nil {
|
if errProc != nil {
|
||||||
cmd.logger.Error(errProc.Error())
|
cmd.logger.ErrorContext(cmd.ctx, errProc.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return 62, fmt.Errorf("context done: %w", cmd.ctx.Err())
|
return 62, fmt.Errorf("context done: %w", cmd.ctx.Err())
|
||||||
@@ -135,8 +134,7 @@ func (cmd *Cmd) Exec() (int, error) {
|
|||||||
// pipeOutput creates logs entries according to the process stdout and stderr.
|
// pipeOutput creates logs entries according to the process stdout and stderr.
|
||||||
// It does nothing if the logging level is not debug.
|
// It does nothing if the logging level is not debug.
|
||||||
func (cmd *Cmd) pipeOutput() error {
|
func (cmd *Cmd) pipeOutput() error {
|
||||||
checkedEntry := cmd.logger.Check(zap.DebugLevel, "check for debug level before piping unix process output")
|
if !cmd.logger.Enabled(cmd.ctx, slog.LevelDebug) {
|
||||||
if checkedEntry == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,12 +150,12 @@ func (cmd *Cmd) pipeOutput() error {
|
|||||||
|
|
||||||
// logCommandOutput creates logs entries according to a reader
|
// logCommandOutput creates logs entries according to a reader
|
||||||
// (either stdout or stderr).
|
// (either stdout or stderr).
|
||||||
logCommandOutput := func(logger *zap.Logger, reader io.ReadCloser) {
|
logCommandOutput := func(logger *slog.Logger, reader io.ReadCloser) {
|
||||||
r := bufio.NewReader(reader)
|
r := bufio.NewReader(reader)
|
||||||
defer func(reader io.ReadCloser) {
|
defer func(reader io.ReadCloser) {
|
||||||
err := reader.Close()
|
err := reader.Close()
|
||||||
if err != nil {
|
if err != nil && !strings.Contains(err.Error(), "file already closed") {
|
||||||
logger.Error(fmt.Sprintf("close reader: %s", err))
|
logger.ErrorContext(cmd.ctx, fmt.Sprintf("close reader: %s", err))
|
||||||
}
|
}
|
||||||
}(reader)
|
}(reader)
|
||||||
|
|
||||||
@@ -165,20 +163,20 @@ func (cmd *Cmd) pipeOutput() error {
|
|||||||
line, _, err := r.ReadLine()
|
line, _, err := r.ReadLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
|
if err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
|
||||||
logger.Error(fmt.Sprintf("pipe unix process output error: %s", err))
|
logger.ErrorContext(cmd.ctx, fmt.Sprintf("pipe unix process output error: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(line) != 0 {
|
if len(line) != 0 {
|
||||||
logger.Debug(string(line))
|
logger.DebugContext(cmd.ctx, string(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go logCommandOutput(cmd.logger.Named("stdout"), stdout)
|
go logCommandOutput(cmd.logger.With(slog.String("logger", "stdout")), stdout)
|
||||||
go logCommandOutput(cmd.logger.Named("stderr"), stderr)
|
go logCommandOutput(cmd.logger.With(slog.String("logger", "stderr")), stderr)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -196,13 +194,13 @@ func (cmd *Cmd) Kill() error {
|
|||||||
|
|
||||||
err := syscall.Kill(-cmd.process.Process.Pid, syscall.SIGKILL)
|
err := syscall.Kill(-cmd.process.Process.Pid, syscall.SIGKILL)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cmd.logger.Debug("unix process killed")
|
cmd.logger.DebugContext(cmd.ctx, "unix process killed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the process does not exist anymore, the error is irrelevant.
|
// If the process does not exist anymore, the error is irrelevant.
|
||||||
if strings.Contains(err.Error(), "no such process") {
|
if strings.Contains(err.Error(), "no such process") {
|
||||||
cmd.logger.Debug("unix process already killed")
|
cmd.logger.DebugContext(cmd.ctx, "unix process already killed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,317 +0,0 @@
|
|||||||
package gotenberg
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCommand(t *testing.T) {
|
|
||||||
cmd := Command(zap.NewNop(), "foo")
|
|
||||||
if !cmd.process.SysProcAttr.Setpgid {
|
|
||||||
t.Error("expected cmd.process.SysProcAttr.Setpgid to be true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCommandContext(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
ctx context.Context
|
|
||||||
expectCommandContextError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
ctx: context.Background(),
|
|
||||||
expectCommandContextError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "nil context",
|
|
||||||
ctx: nil,
|
|
||||||
expectCommandContextError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
cmd, err := CommandContext(tc.ctx, zap.NewNop(), "foo")
|
|
||||||
|
|
||||||
if err == nil && !cmd.process.SysProcAttr.Setpgid {
|
|
||||||
t.Fatal("expected cmd.process.SysProcAttr.Setpgid to be true")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tc.expectCommandContextError && err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tc.expectCommandContextError && err == nil {
|
|
||||||
t.Fatal("expected error but got none")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmd_Start(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
cmd *Cmd
|
|
||||||
expectStartError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
cmd: Command(zap.NewNop(), "echo", "Hello", "World"),
|
|
||||||
expectStartError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "start error",
|
|
||||||
cmd: Command(zap.NewNop(), "foo"),
|
|
||||||
expectStartError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
err := tc.cmd.Start()
|
|
||||||
|
|
||||||
if !tc.expectStartError && err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tc.expectStartError && err == nil {
|
|
||||||
t.Fatal("expected error but got none")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmd_Wait(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
cmd *Cmd
|
|
||||||
expectWaitError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewNop(), "echo", "Hello", "World")
|
|
||||||
err := cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
expectWaitError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "wait error",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewNop(), "echo", "Hello", "World")
|
|
||||||
err := cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
err = cmd.Kill()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
expectWaitError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
err := tc.cmd.Wait()
|
|
||||||
|
|
||||||
if !tc.expectWaitError && err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tc.expectWaitError && err == nil {
|
|
||||||
t.Fatal("expected error but got none")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmd_Exec(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
cmd *Cmd
|
|
||||||
timeout time.Duration
|
|
||||||
expectExecError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd, err := CommandContext(context.Background(), zap.NewNop(), "echo", "Hello", "World")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error from CommandContext(), but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
expectExecError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "nil context",
|
|
||||||
cmd: Command(zap.NewNop(), "echo", "Hello", "World"),
|
|
||||||
expectExecError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "start error",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd, err := CommandContext(context.Background(), zap.NewNop(), "foo")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
expectExecError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "context done",
|
|
||||||
cmd: Command(zap.NewNop(), "sleep", "2"),
|
|
||||||
timeout: time.Duration(1) * time.Second,
|
|
||||||
expectExecError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
if tc.timeout > 0 {
|
|
||||||
ctx, cancel := context.WithTimeout(context.TODO(), tc.timeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
tc.cmd.ctx = ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := tc.cmd.Exec()
|
|
||||||
|
|
||||||
if !tc.expectExecError && err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tc.expectExecError && err == nil {
|
|
||||||
t.Fatal("expected error but got none")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmd_pipeOutput(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
cmd *Cmd
|
|
||||||
run bool
|
|
||||||
expectPipeOutputError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
cmd: Command(zap.NewExample(), "echo", "Hello", "World"),
|
|
||||||
run: true,
|
|
||||||
expectPipeOutputError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "no debug, no pipe",
|
|
||||||
cmd: Command(zap.NewNop(), "echo", "Hello", "World"),
|
|
||||||
run: false,
|
|
||||||
expectPipeOutputError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "stdout already piped",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewExample(), "echo", "Hello", "World")
|
|
||||||
_, err := cmd.process.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
run: false,
|
|
||||||
expectPipeOutputError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "stderr already piped",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewExample(), "echo", "Hello", "World")
|
|
||||||
_, err := cmd.process.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
run: false,
|
|
||||||
expectPipeOutputError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
err := tc.cmd.pipeOutput()
|
|
||||||
|
|
||||||
if tc.run {
|
|
||||||
errStart := tc.cmd.process.Start()
|
|
||||||
if errStart != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tc.expectPipeOutputError && err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tc.expectPipeOutputError && err == nil {
|
|
||||||
t.Fatal("expected error but got none")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmd_Kill(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
scenario string
|
|
||||||
cmd *Cmd
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scenario: "nominal behavior",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewNop(), "sleep", "60")
|
|
||||||
err := cmd.process.Start()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "no process",
|
|
||||||
cmd: &Cmd{logger: zap.NewNop()},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: "process already killed",
|
|
||||||
cmd: func() *Cmd {
|
|
||||||
cmd := Command(zap.NewNop(), "sleep", "60")
|
|
||||||
err := cmd.process.Start()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
err = cmd.Kill()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.scenario, func(t *testing.T) {
|
|
||||||
err := tc.cmd.Kill()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error but got: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,12 +5,12 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is a struct which helps to initialize modules. When provisioning, a
|
// Context is a struct that helps to initialize modules. When provisioning, a
|
||||||
// module may use the context to get other modules that it needs internally.
|
// module may use the context to get other modules that it needs internally.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
flags ParsedFlags
|
flags ParsedFlags
|
||||||
descriptors []ModuleDescriptor
|
descriptors []ModuleDescriptor
|
||||||
moduleInstances map[string]interface{}
|
moduleInstances map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext creates a [Context].
|
// NewContext creates a [Context].
|
||||||
@@ -22,7 +22,7 @@ func NewContext(
|
|||||||
return &Context{
|
return &Context{
|
||||||
flags: flags,
|
flags: flags,
|
||||||
descriptors: descriptors,
|
descriptors: descriptors,
|
||||||
moduleInstances: make(map[string]interface{}),
|
moduleInstances: make(map[string]any),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func (ctx *Context) ParsedFlags() ParsedFlags {
|
|||||||
//
|
//
|
||||||
// If the module has not yet been initialized, this method
|
// If the module has not yet been initialized, this method
|
||||||
// initializes it. Otherwise, returns the already initialized instance.
|
// initializes it. Otherwise, returns the already initialized instance.
|
||||||
func (ctx *Context) Module(kind interface{}) (interface{}, error) {
|
func (ctx *Context) Module(kind any) (any, error) {
|
||||||
mods, err := ctx.Modules(kind)
|
mods, err := ctx.Modules(kind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get module: %w", err)
|
return nil, fmt.Errorf("get module: %w", err)
|
||||||
@@ -58,7 +58,7 @@ func (ctx *Context) Module(kind interface{}) (interface{}, error) {
|
|||||||
return mods[0], nil
|
return mods[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modules returns the list of modules which satisfies the requested interface.
|
// Modules return the list of modules which satisfies the requested interface.
|
||||||
//
|
//
|
||||||
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
|
// func (m *YourModule) Provision(ctx *gotenberg.Context) error {
|
||||||
// mods, _ := ctx.Modules(new(ModuleInterface))
|
// mods, _ := ctx.Modules(new(ModuleInterface))
|
||||||
@@ -70,10 +70,10 @@ func (ctx *Context) Module(kind interface{}) (interface{}, error) {
|
|||||||
//
|
//
|
||||||
// If one or more modules have not yet been initialized, this method
|
// If one or more modules have not yet been initialized, this method
|
||||||
// initializes them. Otherwise, returns the already initialized instances.
|
// initializes them. Otherwise, returns the already initialized instances.
|
||||||
func (ctx *Context) Modules(kind interface{}) ([]interface{}, error) {
|
func (ctx *Context) Modules(kind any) ([]any, error) {
|
||||||
realKind := reflect.TypeOf(kind).Elem()
|
realKind := reflect.TypeOf(kind).Elem()
|
||||||
|
|
||||||
var mods []interface{}
|
var mods []any
|
||||||
|
|
||||||
for _, desc := range ctx.descriptors {
|
for _, desc := range ctx.descriptors {
|
||||||
newInstance := desc.New()
|
newInstance := desc.New()
|
||||||
@@ -101,7 +101,7 @@ func (ctx *Context) Modules(kind interface{}) ([]interface{}, error) {
|
|||||||
|
|
||||||
// loadModule calls the Provision and/or Validate methods of the requested
|
// loadModule calls the Provision and/or Validate methods of the requested
|
||||||
// module if it satisfies the [Provisioner] and/or [Validator] interfaces.
|
// module if it satisfies the [Provisioner] and/or [Validator] interfaces.
|
||||||
func (ctx *Context) loadModule(id string, instance interface{}) error {
|
func (ctx *Context) loadModule(id string, instance any) error {
|
||||||
if prov, ok := instance.(Provisioner); ok {
|
if prov, ok := instance.(Provisioner); ok {
|
||||||
// The instance can be provisioned.
|
// The instance can be provisioned.
|
||||||
err := prov.Provision(ctx)
|
err := prov.Provision(ctx)
|
||||||
|
|||||||
@@ -5,28 +5,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewContext(t *testing.T) {
|
|
||||||
if NewContext(ParsedFlags{}, nil) == nil {
|
|
||||||
t.Error("expected a non-nil value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_ParsedFlags(t *testing.T) {
|
|
||||||
ctx := NewContext(ParsedFlags{}, nil)
|
|
||||||
|
|
||||||
actual := ctx.ParsedFlags()
|
|
||||||
expect := ParsedFlags{}
|
|
||||||
|
|
||||||
if actual != expect {
|
|
||||||
t.Errorf("expected %v but got %v", expect, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_Module(t *testing.T) {
|
func TestContext_Module(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
scenario string
|
scenario string
|
||||||
mods []ModuleDescriptor
|
mods []ModuleDescriptor
|
||||||
kind interface{}
|
kind any
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -97,7 +80,7 @@ func TestContext_Modules(t *testing.T) {
|
|||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
scenario string
|
scenario string
|
||||||
mods []ModuleDescriptor
|
mods []ModuleDescriptor
|
||||||
kind interface{}
|
kind any
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -168,12 +151,12 @@ func TestContext_Modules(t *testing.T) {
|
|||||||
func TestContext_loadModule(t *testing.T) {
|
func TestContext_loadModule(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
scenario string
|
scenario string
|
||||||
instance interface{}
|
instance any
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
scenario: "module with error on provision",
|
scenario: "module with error on provision",
|
||||||
instance: func() interface{} {
|
instance: func() any {
|
||||||
mod := &struct {
|
mod := &struct {
|
||||||
ModuleMock
|
ModuleMock
|
||||||
ProvisionerMock
|
ProvisionerMock
|
||||||
@@ -188,7 +171,7 @@ func TestContext_loadModule(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "module with error on validation",
|
scenario: "module with error on validation",
|
||||||
instance: func() interface{} {
|
instance: func() any {
|
||||||
mod := &struct {
|
mod := &struct {
|
||||||
ModuleMock
|
ModuleMock
|
||||||
ValidatorMock
|
ValidatorMock
|
||||||
@@ -203,7 +186,7 @@ func TestContext_loadModule(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "success",
|
scenario: "success",
|
||||||
instance: func() interface{} {
|
instance: func() any {
|
||||||
mod := &struct {
|
mod := &struct {
|
||||||
ModuleMock
|
ModuleMock
|
||||||
ValidatorMock
|
ValidatorMock
|
||||||
|
|||||||
71
pkg/gotenberg/debug.go
Normal file
71
pkg/gotenberg/debug.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package gotenberg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DebugInfo gathers data for debugging.
|
||||||
|
type DebugInfo struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Timezone string `json:"timezone"`
|
||||||
|
Architecture string `json:"architecture"`
|
||||||
|
Modules []string `json:"modules"`
|
||||||
|
ModulesAdditionalData map[string]map[string]any `json:"modules_additional_data"`
|
||||||
|
Flags map[string]any `json:"flags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildDebug builds the debug data from modules.
|
||||||
|
func BuildDebug(ctx *Context) {
|
||||||
|
debugMu.Lock()
|
||||||
|
defer debugMu.Unlock()
|
||||||
|
|
||||||
|
debug = &DebugInfo{
|
||||||
|
Version: Version,
|
||||||
|
Timezone: time.Now().Location().String(),
|
||||||
|
Architecture: runtime.GOARCH,
|
||||||
|
Modules: make([]string, len(ctx.moduleInstances)),
|
||||||
|
ModulesAdditionalData: make(map[string]map[string]any),
|
||||||
|
Flags: make(map[string]any),
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for ID, mod := range ctx.moduleInstances {
|
||||||
|
debug.Modules[i] = ID
|
||||||
|
i++
|
||||||
|
|
||||||
|
debuggable, ok := mod.(Debuggable)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
debug.ModulesAdditionalData[ID] = debuggable.Debug()
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(AlphanumericSort(debug.Modules))
|
||||||
|
|
||||||
|
ctx.ParsedFlags().VisitAll(func(f *flag.Flag) {
|
||||||
|
debug.Flags[f.Name] = f.Value.String()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug returns the debug data.
|
||||||
|
func Debug() DebugInfo {
|
||||||
|
debugMu.Lock()
|
||||||
|
defer debugMu.Unlock()
|
||||||
|
|
||||||
|
if debug == nil {
|
||||||
|
return DebugInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *debug
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
debug *DebugInfo
|
||||||
|
debugMu sync.Mutex
|
||||||
|
)
|
||||||
75
pkg/gotenberg/debug_test.go
Normal file
75
pkg/gotenberg/debug_test.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package gotenberg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildDebug(t *testing.T) {
|
||||||
|
if !reflect.DeepEqual(Debug(), DebugInfo{}) {
|
||||||
|
t.Errorf("Debug() should return empty debug data")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Setenv("TZ", "UTC")
|
||||||
|
|
||||||
|
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
|
||||||
|
fs.String("foo", "bar", "Set foo")
|
||||||
|
ctx := NewContext(ParsedFlags{
|
||||||
|
FlagSet: fs,
|
||||||
|
}, func() []ModuleDescriptor {
|
||||||
|
mod1 := &struct {
|
||||||
|
ModuleMock
|
||||||
|
}{}
|
||||||
|
mod1.DescriptorMock = func() ModuleDescriptor {
|
||||||
|
return ModuleDescriptor{ID: "foo", New: func() Module { return mod1 }}
|
||||||
|
}
|
||||||
|
mod2 := &struct {
|
||||||
|
ModuleMock
|
||||||
|
DebuggableMock
|
||||||
|
}{}
|
||||||
|
mod2.DescriptorMock = func() ModuleDescriptor {
|
||||||
|
return ModuleDescriptor{ID: "bar", New: func() Module { return mod2 }}
|
||||||
|
}
|
||||||
|
mod2.DebugMock = func() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []ModuleDescriptor{mod1.Descriptor(), mod2.Descriptor()}
|
||||||
|
}())
|
||||||
|
|
||||||
|
// Load modules.
|
||||||
|
_, err := ctx.Modules(new(Module))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build debug data.
|
||||||
|
BuildDebug(ctx)
|
||||||
|
|
||||||
|
expect := DebugInfo{
|
||||||
|
Version: Version,
|
||||||
|
Timezone: "UTC",
|
||||||
|
Architecture: runtime.GOARCH,
|
||||||
|
Modules: []string{
|
||||||
|
"bar",
|
||||||
|
"foo",
|
||||||
|
},
|
||||||
|
ModulesAdditionalData: map[string]map[string]any{
|
||||||
|
"bar": {
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Flags: map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expect, Debug()) {
|
||||||
|
t.Errorf("expected '%+v', bug got '%+v'", expect, Debug())
|
||||||
|
}
|
||||||
|
}
|
||||||
35
pkg/gotenberg/env.go
Normal file
35
pkg/gotenberg/env.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package gotenberg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringEnv retrieves the value of the environment variable named by the key.
|
||||||
|
// If the variable is present in the environment and not empty, the value is
|
||||||
|
// returned.
|
||||||
|
func StringEnv(key string) (string, error) {
|
||||||
|
val, ok := os.LookupEnv(key)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("environment variable '%s' does not exist", key)
|
||||||
|
}
|
||||||
|
if val == "" {
|
||||||
|
return "", fmt.Errorf("environment variable '%s' is empty", key)
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntEnv relies on [StringEnv] and converts the values if it exists and is not
|
||||||
|
// empty.
|
||||||
|
func IntEnv(key string) (int, error) {
|
||||||
|
val, err := StringEnv(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
intVal, err := strconv.Atoi(val)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("get int value of environment variable '%s': %w", key, err)
|
||||||
|
}
|
||||||
|
return intVal, nil
|
||||||
|
}
|
||||||
134
pkg/gotenberg/env_test.go
Normal file
134
pkg/gotenberg/env_test.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package gotenberg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringEnv(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
scenario string
|
||||||
|
key string
|
||||||
|
setEnv func()
|
||||||
|
expectVal string
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
scenario: "non-existing environment variable",
|
||||||
|
key: "NON_EXISTING",
|
||||||
|
expectVal: "",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "empty environment variable",
|
||||||
|
key: "EMPTY_STRING",
|
||||||
|
setEnv: func() {
|
||||||
|
err := os.Setenv("EMPTY_STRING", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectVal: "",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "success",
|
||||||
|
key: "EXISTING_STRING_VALUE",
|
||||||
|
setEnv: func() {
|
||||||
|
err := os.Setenv("EXISTING_STRING_VALUE", "foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectVal: "foo",
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.scenario, func(t *testing.T) {
|
||||||
|
if tc.setEnv != nil {
|
||||||
|
tc.setEnv()
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := StringEnv(tc.key)
|
||||||
|
|
||||||
|
if !tc.expectError && err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectError && err == nil {
|
||||||
|
t.Fatal("expected error but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectVal != val {
|
||||||
|
t.Errorf("expected value '%s' but got '%s'", tc.expectVal, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntEnv(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
scenario string
|
||||||
|
key string
|
||||||
|
setEnv func()
|
||||||
|
expectVal int
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
scenario: "empty environment variable",
|
||||||
|
key: "EMPTY_INT",
|
||||||
|
setEnv: func() {
|
||||||
|
err := os.Setenv("EMPTY_INT", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectVal: 0,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "non-integer value",
|
||||||
|
key: "NON_INTEGER",
|
||||||
|
setEnv: func() {
|
||||||
|
err := os.Setenv("NON_INTEGER", "foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectVal: 0,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "success",
|
||||||
|
key: "EXISTING_INT_VALUE",
|
||||||
|
setEnv: func() {
|
||||||
|
err := os.Setenv("EXISTING_INT_VALUE", "123")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectVal: 123,
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.scenario, func(t *testing.T) {
|
||||||
|
if tc.setEnv != nil {
|
||||||
|
tc.setEnv()
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := IntEnv(tc.key)
|
||||||
|
|
||||||
|
if !tc.expectError && err != nil {
|
||||||
|
t.Fatalf("expected no error but got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectError && err == nil {
|
||||||
|
t.Fatal("expected error but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectVal != val {
|
||||||
|
t.Errorf("expected value %d but got %d", tc.expectVal, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user