Compare commits
305 commits
verbose-er
...
main
Author | SHA1 | Date | |
---|---|---|---|
3bc72f5bb8 | |||
e9fdfdf520 | |||
7fa2a8056d | |||
dfb46d76a5 | |||
39c6b95af8 | |||
0935eae193 | |||
58a1b005e9 | |||
bba684d76e | |||
ec150dde62 | |||
76d4ad16dc | |||
126ae37845 | |||
e9f1915655 | |||
7448333d7c | |||
e8555798e4 | |||
cf4d1e450c | |||
a661eaf3ca | |||
f4da27f63f | |||
e764534487 | |||
6093d160e8 | |||
4d8dc95d8e | |||
e6f39eab21 | |||
0cb4bc43f9 | |||
5b5bc0ab96 | |||
b139865f89 | |||
e4fa06fc42 | |||
4fa849b72b | |||
48bbbe6f6e | |||
bf843edb80 | |||
5e8c21c521 | |||
3bc3a0cd7e | |||
56bc215f26 | |||
678b75ae6f | |||
d133b281f9 | |||
581449fba4 | |||
b38876d9ef | |||
90c4d4ec9d | |||
c0daa85612 | |||
0bdd13cf8a | |||
1bba35963a | |||
2b7fe54f76 | |||
e96581754c | |||
4034b0022b | |||
87cc56cdd7 | |||
a9d98a6d0c | |||
671a3b8cbb | |||
011fc848af | |||
c5af5c9198 | |||
afec1fdd0c | |||
6513e00e54 | |||
3cc6206d06 | |||
48452baac5 | |||
5875642777 | |||
58d8d46a0c | |||
6e57204ce5 | |||
d3f1204932 | |||
305c9a6bd0 | |||
751bc26a21 | |||
202c07150c | |||
f5c75a31f5 | |||
7c24477348 | |||
237691f79f | |||
c6c8de9b0f | |||
a7a00756bc | |||
e822e3d0f0 | |||
bbd12cda4e | |||
adcf93d321 | |||
c9df6082ae | |||
5825bcbf47 | |||
|
b8f7b72a61 | ||
|
f4d30706b7 | ||
|
72cd6a65d2 | ||
|
fde5061bf3 | ||
0dcb375e15 | |||
c6872458e2 | |||
a5a653b213 | |||
f12d43b9bc | |||
5f18c7ddb3 | |||
c92923f6b9 | |||
2aec5b44d2 | |||
52622b1f2d | |||
822bebc26f | |||
0ba623c560 | |||
147cb1bd72 | |||
56dc19322a | |||
ee20925e04 | |||
2455ea0ff0 | |||
739940cdd3 | |||
47dc81860a | |||
308c86595c | |||
45745f3ebd | |||
5b5249eb55 | |||
d2a3e60edf | |||
8324727b8a | |||
c79c0c1a7f | |||
d5c9bae212 | |||
2914be8a88 | |||
bfc55293dc | |||
9a0573bc33 | |||
701047fd4f | |||
9638450ef6 | |||
d90f68ce1a | |||
f3f51b165a | |||
29d439e82a | |||
4d8961557c | |||
3e49e31e66 | |||
5053b79ad4 | |||
215a9bf0fe | |||
97978e9950 | |||
7375ba16cc | |||
07cf837ac6 | |||
6399a1dfeb | |||
36df9f486b | |||
617d909438 | |||
bcccfd8b9c | |||
f7897a574d | |||
c6217bd0a2 | |||
e5d1203435 | |||
78824ea38b | |||
288247be8e | |||
bc06c34ea3 | |||
03c4229cf0 | |||
32ae4f2a6f | |||
3bbae609d7 | |||
b8f6129146 | |||
ef2efc40f7 | |||
b3a612c938 | |||
|
edd2ae5743 | ||
|
fc92260a43 | ||
7e5e66d933 | |||
9fdd81d4b0 | |||
5d81903870 | |||
d643bba325 | |||
4c0524aafe | |||
1db263d13f | |||
58bfd98af9 | |||
d3e8c19f02 | |||
bdca4f224f | |||
331c57a952 | |||
cea54b0945 | |||
d8396402b5 | |||
1afa34dba3 | |||
a5923aef5f | |||
c669d8f7b5 | |||
22397a369e | |||
d5c711fa88 | |||
63a043dfee | |||
3ccac186c9 | |||
686c703f7d | |||
17d93c34ec | |||
95ca351ae8 | |||
d15195a8e0 | |||
b3841a6801 | |||
3d83ec19e1 | |||
e7000ec408 | |||
bf74fd1a73 | |||
954a2f735b | |||
f8ec35860a | |||
d67dfb7378 | |||
6dc10b77e7 | |||
b77a8fd67d | |||
951e66776d | |||
1a946151b7 | |||
8132958b16 | |||
fea084c09a | |||
ad6287aafe | |||
509216c001 | |||
62e3f58f81 | |||
898b8e8900 | |||
17ae55f3c0 | |||
ec0844d53b | |||
b6b2e6d9b5 | |||
46b8172f11 | |||
d160c551e1 | |||
1f2e1d9569 | |||
66691c9ee9 | |||
dce22ba7b3 | |||
25887841a2 | |||
57b88664d2 | |||
ddb173af46 | |||
a9d01c5907 | |||
46c8a1751c | |||
dea2d7f3ed | |||
06a650fd77 | |||
1fff46986e | |||
ab8bb7f400 | |||
2be0a44aa8 | |||
7d2d197cbb | |||
2e24e79a4c | |||
d555b34eef | |||
f9daf87262 | |||
7aa45910e9 | |||
45884d1032 | |||
bfcdcbb78a | |||
caaf804fd3 | |||
a876fdc799 | |||
e0150e6fcc | |||
b861087e9d | |||
700a0a2f4f | |||
ee58151a8d | |||
f30609288a | |||
2217e5c8d1 | |||
3cfb453454 | |||
5d2596bd3f | |||
cb41ad0719 | |||
db8b41be19 | |||
f4be6e0c8b | |||
5f5743354c | |||
2469fd2f5b | |||
39591c8aa9 | |||
337a790044 | |||
935baa9932 | |||
369f62ff38 | |||
074e77196e | |||
88253f49ac | |||
2fc59f105b | |||
00202edecc | |||
31ac285df0 | |||
0952ec57a8 | |||
911158f882 | |||
f3bf8cb335 | |||
c02440ac65 | |||
8d4921ea70 | |||
09bf3f5d44 | |||
6dbbb8f2a1 | |||
e6450b796f | |||
c15503b7a0 | |||
2e5e1ea0ee | |||
483c2b8bba | |||
2c2a88eced | |||
577c717a87 | |||
1585f15582 | |||
9517e9081e | |||
355bd477af | |||
48f7d9c29e | |||
3cbf18792b | |||
e38acb39c1 | |||
03e32418e8 | |||
1cc5c565f3 | |||
5a39ac0970 | |||
777dfff541 | |||
074e62d16e | |||
3ccfa81155 | |||
9ffbba0765 | |||
4efddcc104 | |||
b7540151fc | |||
ca88c63407 | |||
41c41cf9c3 | |||
a53c28b690 | |||
8ae03f5811 | |||
2ead8cc31b | |||
bf2d68bddc | |||
e21155fdec | |||
43988291c6 | |||
f04477f137 | |||
587c8893f0 | |||
aea4a31445 | |||
7002683a84 | |||
f2fd1e3b07 | |||
0a40e5e213 | |||
146e11a1de | |||
a15030adaa | |||
3c9a86f67c | |||
cb48674864 | |||
771ffe5229 | |||
355c457d57 | |||
9cb77f395f | |||
8ce3c74c34 | |||
e927ec9fcf | |||
c93875f491 | |||
459a182388 | |||
1d9674b097 | |||
0219127416 | |||
5c3d07e58c | |||
8b11a4fa61 | |||
9c44bebd5d | |||
6b1ffb6e99 | |||
b7acaab2a9 | |||
ac06c71a1a | |||
039b9fe2f0 | |||
9016592832 | |||
6332b738e3 | |||
55daeb69f1 | |||
153d4bbf9a | |||
1ae9593537 | |||
0a44d6e363 | |||
9341c147ae | |||
a6f6b9715e | |||
e9c6c95299 | |||
eb5be21824 | |||
036eb53972 | |||
7ff93b18d5 | |||
4bc4af52cd | |||
d2bc3cd9f3 | |||
1cc7221c44 | |||
15544e0ba0 | |||
cf091b64e3 | |||
54f0ad2297 | |||
b8f55aa10d | |||
7a55d0f3a6 | |||
93c9a542d9 | |||
5755133d89 | |||
66c78da0c2 | |||
a4cdf051ff | |||
e1639974e3 | |||
186f057b2b |
82 changed files with 2240 additions and 877 deletions
42
.github/workflows/stable.yml
vendored
42
.github/workflows/stable.yml
vendored
|
@ -1,42 +0,0 @@
|
||||||
name: stable
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: stable build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Use python 3.x
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
|
|
||||||
- name: install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
- name: build stable release
|
|
||||||
env:
|
|
||||||
TWINE_USERNAME: __token__
|
|
||||||
TWINE_PASSWORD: ${{ secrets.PYPI_DDA }}
|
|
||||||
run: |
|
|
||||||
pyb -P version=${{ github.ref }} publish upload
|
|
||||||
|
|
||||||
- name: Create GH Release
|
|
||||||
id: create_release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ github.ref }}
|
|
||||||
release_name: Release ${{ github.ref }}
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
|
|
30
.github/workflows/unstable.yml
vendored
30
.github/workflows/unstable.yml
vendored
|
@ -1,30 +0,0 @@
|
||||||
name: unstable
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '![0-9]+.[0-9]+.[0-9]+'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: unstable
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Use python 3.x
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
|
|
||||||
- name: install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
- name: build unstable release
|
|
||||||
env:
|
|
||||||
TWINE_USERNAME: __token__
|
|
||||||
TWINE_PASSWORD: ${{ secrets.PYPI_DDA }}
|
|
||||||
run: |
|
|
||||||
pyb publish upload
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -109,3 +109,6 @@ venv.bak/
|
||||||
|
|
||||||
.clj-kondo/
|
.clj-kondo/
|
||||||
.lsp/
|
.lsp/
|
||||||
|
.calva/
|
||||||
|
.cpcache/
|
||||||
|
infrastructure/backup/image/resources/backup-repository-state.edn
|
||||||
|
|
|
@ -1,17 +1,89 @@
|
||||||
image: "domaindrivenarchitecture/devops-build:4.0.8"
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- python --version
|
|
||||||
- python -m pip install --upgrade pip
|
|
||||||
- pip install -r requirements.txt
|
|
||||||
- export IMAGE_TAG=$CI_IMAGE_TAG
|
|
||||||
- export IMAGE_DOCKERHUB_USER=$DOCKERHUB_USER
|
|
||||||
- export IMAGE_DOCKERHUB_PASSWORD=$DOCKERHUB_PASSWORD
|
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
|
- lint&test
|
||||||
|
- upload
|
||||||
- image
|
- image
|
||||||
|
|
||||||
devops-build-image-test-publish:
|
.py: &py
|
||||||
|
image: "domaindrivenarchitecture/ddadevops-python:4.10.7"
|
||||||
|
before_script:
|
||||||
|
- export RELEASE_ARTIFACT_TOKEN=$MEISSA_REPO_BUERO_RW
|
||||||
|
- python --version
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
|
||||||
|
.img: &img
|
||||||
|
image: "domaindrivenarchitecture/ddadevops-dind:4.10.7"
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
before_script:
|
||||||
|
- export IMAGE_DOCKERHUB_USER=$DOCKERHUB_USER
|
||||||
|
- export IMAGE_DOCKERHUB_PASSWORD=$DOCKERHUB_PASSWORD
|
||||||
|
- export IMAGE_TAG=$CI_COMMIT_TAG
|
||||||
|
|
||||||
|
.tag_only: &tag_only
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||||
|
when: never
|
||||||
|
- if: '$CI_COMMIT_TAG =~ /^[0-9]+\.[0-9]+\.[0-9]+$/'
|
||||||
|
|
||||||
|
lint:
|
||||||
|
<<: *py
|
||||||
|
stage: lint&test
|
||||||
|
script:
|
||||||
|
- pip install -r dev_requirements.txt
|
||||||
|
- pyb lint
|
||||||
|
|
||||||
|
pytest:
|
||||||
|
<<: *py
|
||||||
|
stage: lint&test
|
||||||
|
script:
|
||||||
|
- pip install -r dev_requirements.txt
|
||||||
|
- pyb test
|
||||||
|
|
||||||
|
pypi-stable:
|
||||||
|
<<: *py
|
||||||
|
<<: *tag_only
|
||||||
|
stage: upload
|
||||||
|
script:
|
||||||
|
- pyb -P version=$CI_COMMIT_TAG publish upload publish_artifacts
|
||||||
|
|
||||||
|
clj-cljs-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
stage: image
|
stage: image
|
||||||
script:
|
script:
|
||||||
- cd infrastructure/devops-build && pyb image
|
- cd infrastructure/clj-cljs && pyb image publish
|
||||||
|
|
||||||
|
clj-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
|
stage: image
|
||||||
|
script:
|
||||||
|
- cd infrastructure/clj && pyb image publish
|
||||||
|
|
||||||
|
python-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
|
stage: image
|
||||||
|
script:
|
||||||
|
- cd infrastructure/python && pyb image publish
|
||||||
|
|
||||||
|
dind-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
|
stage: image
|
||||||
|
script:
|
||||||
|
- cd infrastructure/dind && pyb image publish
|
||||||
|
|
||||||
|
ddadevops-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
|
stage: image
|
||||||
|
script:
|
||||||
|
- cd infrastructure/ddadevops && pyb image publish
|
||||||
|
|
||||||
|
kotlin-image-publish:
|
||||||
|
<<: *img
|
||||||
|
<<: *tag_only
|
||||||
|
stage: image
|
||||||
|
script:
|
||||||
|
- cd infrastructure/kotlin && pyb image publish
|
||||||
|
|
52
README.md
52
README.md
|
@ -1,8 +1,7 @@
|
||||||
# dda-devops-build
|
# dda-devops-build
|
||||||
|
|
||||||
[![Slack](https://img.shields.io/badge/chat-clojurians-green.svg?style=flat)](https://clojurians.slack.com/messages/#dda-pallet/) | [<img src="https://meissa-gmbh.de/img/community/Mastodon_Logotype.svg" width=20 alt="team@social.meissa-gmbh.de"> team@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@team) | [Website & Blog](https://domaindrivenarchitecture.org)
|
[![Slack](https://img.shields.io/badge/chat-clojurians-green.svg?style=flat)](https://clojurians.slack.com/messages/#dda-pallet/) | [<img src="https://domaindrivenarchitecture.org/img/delta-chat.svg" width=20 alt="DeltaChat"> chat over e-mail](mailto:buero@meissa-gmbh.de?subject=community-chat) | [<img src="https://meissa.de/images/parts/contact/mastodon36_hue9b2464f10b18e134322af482b9c915e_5501_filter_14705073121015236177.png" width=20 alt="M"> meissa@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@meissa) | [Blog](https://domaindrivenarchitecture.org) | [Website](https://meissa.de)
|
||||||
|
|
||||||
![release prod](https://github.com/DomainDrivenArchitecture/dda-devops-build/workflows/release%20prod/badge.svg)
|
|
||||||
|
|
||||||
dda-devops-build integrates all the tools we use to work with clouds & provide some nice functions around.
|
dda-devops-build integrates all the tools we use to work with clouds & provide some nice functions around.
|
||||||
|
|
||||||
|
@ -70,12 +69,12 @@ classDiagram
|
||||||
DevopsBuild <|-- ProvsK3sBuild
|
DevopsBuild <|-- ProvsK3sBuild
|
||||||
DevopsBuild <|-- C4kBuild
|
DevopsBuild <|-- C4kBuild
|
||||||
|
|
||||||
link DevopsBuild "./doc/DevopsBuild.md"
|
link DevopsBuild "dda-devops-build/src/doc/DevopsBuild.md"
|
||||||
link DevopsImageBuild "./doc/DevopsImageBuild.md"
|
link DevopsImageBuild "dda-devops-build/src/doc/DevopsImageBuild.md"
|
||||||
link DevopsTerraformBuild "./doc/DevopsTerraformBuild.md"
|
link DevopsTerraformBuild "dda-devops-build/src/doc/DevopsTerraformBuild.md"
|
||||||
link ReleaseMixin "./doc/ReleaseMixin.md"
|
link ReleaseMixin "dda-devops-build/src/doc/ReleaseMixin.md"
|
||||||
link ProvsK3sBuild "doc/ProvsK3sBuild.md"
|
link ProvsK3sBuild "dda-devops-build/src/doc/ProvsK3sBuild.md"
|
||||||
link C4kBuild "doc/C4kBuild.md"
|
link C4kBuild "dda-devops-build/src/doc/C4kBuild.md"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -84,6 +83,10 @@ Principles we follow are:
|
||||||
* Seperate build artefacts from version controlled code
|
* Seperate build artefacts from version controlled code
|
||||||
* Domain Driven Design - in order to stay sustainable
|
* Domain Driven Design - in order to stay sustainable
|
||||||
|
|
||||||
|
## Example Project
|
||||||
|
|
||||||
|
An example project which is using dda-devops-build can be found at: https://repo.prod.meissa.de/meissa/buildtest
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Ensure that yout python3 version is at least Python 3.10
|
Ensure that yout python3 version is at least Python 3.10
|
||||||
|
@ -94,17 +97,9 @@ pip3 install -r requirements.txt
|
||||||
export PATH=$PATH:~/.local/bin
|
export PATH=$PATH:~/.local/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reference
|
## Example Project
|
||||||
|
|
||||||
* [DevopsBuild](./doc/DevopsBuild.md)
|
An example project which is using dda-devops-build can be found at: https://repo.prod.meissa.de/meissa/buildtest
|
||||||
* [DevopsImageBuild](./doc/DevopsImageBuild.md)
|
|
||||||
* [DevopsTerraformBuild](./doc/DevopsTerraformBuild.md)
|
|
||||||
* [AwsProvider](doc/DevopsTerraformBuildWithAwsProvider.md)
|
|
||||||
* [DigitaloceanProvider](doc/DevopsTerraformBuildWithDigitaloceanProvider.md)
|
|
||||||
* [HetznerProvider](doc/DevopsTerraformBuildWithHetznerProvider.md)
|
|
||||||
* [ReleaseMixin](./doc/ReleaseMixin.md)
|
|
||||||
* [ProvsK3sBuild](doc/ProvsK3sBuild.md)
|
|
||||||
* [C4kBuild](doc/C4kBuild.md)
|
|
||||||
|
|
||||||
## Example Build
|
## Example Build
|
||||||
|
|
||||||
|
@ -186,10 +181,23 @@ def destroy(project):
|
||||||
pyb dev publish upload
|
pyb dev publish upload
|
||||||
pip3 install --upgrade ddadevops --pre
|
pip3 install --upgrade ddadevops --pre
|
||||||
|
|
||||||
pyb [patch|minor|major] prepare_release tag_bump_and_push_release
|
pyb [patch|minor|major]
|
||||||
pip3 install --upgrade ddadevops
|
pip3 install --upgrade ddadevops
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
* [DevopsBuild](./doc/DevopsBuild.md)
|
||||||
|
* [DevopsImageBuild](./doc/DevopsImageBuild.md)
|
||||||
|
* [DevopsTerraformBuild](./doc/DevopsTerraformBuild.md)
|
||||||
|
* [AwsProvider](doc/DevopsTerraformBuildWithAwsProvider.md)
|
||||||
|
* [DigitaloceanProvider](doc/DevopsTerraformBuildWithDigitaloceanProvider.md)
|
||||||
|
* [HetznerProvider](doc/DevopsTerraformBuildWithHetznerProvider.md)
|
||||||
|
* [ReleaseMixin](./doc/ReleaseMixin.md)
|
||||||
|
* [ProvsK3sBuild](doc/ProvsK3sBuild.md)
|
||||||
|
* [C4kBuild](doc/C4kBuild.md)
|
||||||
|
|
||||||
|
|
||||||
## Development & mirrors
|
## Development & mirrors
|
||||||
|
|
||||||
Development happens at: https://repo.prod.meissa.de/meissa/dda-devops-build
|
Development happens at: https://repo.prod.meissa.de/meissa/dda-devops-build
|
||||||
|
@ -197,6 +205,7 @@ Development happens at: https://repo.prod.meissa.de/meissa/dda-devops-build
|
||||||
Mirrors are:
|
Mirrors are:
|
||||||
|
|
||||||
* https://gitlab.com/domaindrivenarchitecture/dda-devops-build (issues and PR, CI)
|
* https://gitlab.com/domaindrivenarchitecture/dda-devops-build (issues and PR, CI)
|
||||||
|
* https://github.com/DomainDrivenArchitecture/dda-devops-build
|
||||||
|
|
||||||
For more details about our repository model see: https://repo.prod.meissa.de/meissa/federate-your-repos
|
For more details about our repository model see: https://repo.prod.meissa.de/meissa/federate-your-repos
|
||||||
|
|
||||||
|
@ -204,8 +213,3 @@ For more details about our repository model see: https://repo.prod.meissa.de/mei
|
||||||
|
|
||||||
Copyright © 2021 meissa GmbH
|
Copyright © 2021 meissa GmbH
|
||||||
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
|
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Copyright © 2023 meissa GmbH
|
|
||||||
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
|
|
||||||
|
|
128
build.py
128
build.py
|
@ -33,7 +33,7 @@ default_task = "dev"
|
||||||
name = "ddadevops"
|
name = "ddadevops"
|
||||||
MODULE = "not-used"
|
MODULE = "not-used"
|
||||||
PROJECT_ROOT_PATH = "."
|
PROJECT_ROOT_PATH = "."
|
||||||
version = "4.0.12-dev"
|
version = "4.13.2-dev"
|
||||||
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
|
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
|
||||||
description = __doc__
|
description = __doc__
|
||||||
authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")]
|
authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")]
|
||||||
|
@ -41,20 +41,25 @@ url = "https://repo.prod.meissa.de/meissa/dda-devops-build"
|
||||||
requires_python = ">=3.10" # CHECK IF NEW VERSION EXISTS
|
requires_python = ">=3.10" # CHECK IF NEW VERSION EXISTS
|
||||||
license = "Apache Software License"
|
license = "Apache Software License"
|
||||||
|
|
||||||
|
|
||||||
@init
|
@init
|
||||||
def initialize(project):
|
def initialize(project):
|
||||||
# project.build_depends_on('mockito')
|
# project.build_depends_on('mockito')
|
||||||
# project.build_depends_on('unittest-xml-reporting')
|
# project.build_depends_on('unittest-xml-reporting')
|
||||||
project.build_depends_on("ddadevops>=4.0.0")
|
project.build_depends_on("ddadevops>=4.7.0")
|
||||||
|
|
||||||
project.set_property("verbose", True)
|
project.set_property("verbose", True)
|
||||||
project.get_property("filter_resources_glob").append("main/python/ddadevops/__init__.py")
|
project.get_property("filter_resources_glob").append(
|
||||||
|
"main/python/ddadevops/__init__.py"
|
||||||
|
)
|
||||||
project.set_property("dir_source_unittest_python", "src/test/python")
|
project.set_property("dir_source_unittest_python", "src/test/python")
|
||||||
|
|
||||||
project.set_property("copy_resources_target", "$dir_dist/ddadevops")
|
project.set_property("copy_resources_target", "$dir_dist/ddadevops")
|
||||||
project.get_property("copy_resources_glob").append("LICENSE")
|
project.get_property("copy_resources_glob").append("LICENSE")
|
||||||
project.get_property("copy_resources_glob").append("src/main/resources/terraform/*")
|
project.get_property("copy_resources_glob").append("src/main/resources/terraform/*")
|
||||||
project.get_property("copy_resources_glob").append("src/main/resources/docker/image/resources/*")
|
project.get_property("copy_resources_glob").append(
|
||||||
|
"src/main/resources/docker/image/resources/*"
|
||||||
|
)
|
||||||
project.include_file("ddadevops", "LICENSE")
|
project.include_file("ddadevops", "LICENSE")
|
||||||
project.include_file("ddadevops", "src/main/resources/terraform/*")
|
project.include_file("ddadevops", "src/main/resources/terraform/*")
|
||||||
project.include_file("ddadevops", "src/main/resources/docker/image/resources/*")
|
project.include_file("ddadevops", "src/main/resources/docker/image/resources/*")
|
||||||
|
@ -63,22 +68,25 @@ def initialize(project):
|
||||||
# project.set_property('distutils_upload_sign_identity', '')
|
# project.set_property('distutils_upload_sign_identity', '')
|
||||||
project.set_property("distutils_readme_description", True)
|
project.set_property("distutils_readme_description", True)
|
||||||
project.set_property("distutils_description_overwrite", True)
|
project.set_property("distutils_description_overwrite", True)
|
||||||
project.set_property("distutils_classifiers", [
|
project.set_property(
|
||||||
'License :: OSI Approved :: Apache Software License',
|
"distutils_classifiers",
|
||||||
'Programming Language :: Python',
|
[
|
||||||
'Programming Language :: Python :: 3',
|
"License :: OSI Approved :: Apache Software License",
|
||||||
'Programming Language :: Python :: 3.8',
|
"Programming Language :: Python",
|
||||||
'Programming Language :: Python :: 3.10',
|
"Programming Language :: Python :: 3",
|
||||||
'Operating System :: POSIX :: Linux',
|
"Programming Language :: Python :: 3.8",
|
||||||
'Operating System :: OS Independent',
|
"Programming Language :: Python :: 3.10",
|
||||||
'Development Status :: 5 - Production/Stable',
|
"Operating System :: POSIX :: Linux",
|
||||||
'Environment :: Console',
|
"Operating System :: OS Independent",
|
||||||
'Intended Audience :: Developers',
|
"Development Status :: 5 - Production/Stable",
|
||||||
'License :: OSI Approved :: Apache Software License',
|
"Environment :: Console",
|
||||||
'Topic :: Software Development :: Build Tools',
|
"Intended Audience :: Developers",
|
||||||
'Topic :: Software Development :: Quality Assurance',
|
"License :: OSI Approved :: Apache Software License",
|
||||||
'Topic :: Software Development :: Testing'
|
"Topic :: Software Development :: Build Tools",
|
||||||
])
|
"Topic :: Software Development :: Quality Assurance",
|
||||||
|
"Topic :: Software Development :: Testing",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -88,59 +96,99 @@ def initialize(project):
|
||||||
"build_types": [],
|
"build_types": [],
|
||||||
"mixin_types": ["RELEASE"],
|
"mixin_types": ["RELEASE"],
|
||||||
"release_primary_build_file": "build.py",
|
"release_primary_build_file": "build.py",
|
||||||
|
"release_secondary_build_files": [
|
||||||
|
"infrastructure/python/build.py",
|
||||||
|
"infrastructure/dind/build.py",
|
||||||
|
"infrastructure/ddadevops/build.py",
|
||||||
|
"infrastructure/clj-cljs/build.py",
|
||||||
|
"infrastructure/clj/build.py",
|
||||||
|
"infrastructure/kotlin/build.py",
|
||||||
|
],
|
||||||
|
"release_artifacts": [],
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": "meissa",
|
||||||
|
"release_repository_name": "dda-devops-build",
|
||||||
}
|
}
|
||||||
|
|
||||||
build = ReleaseMixin(project, input)
|
build = ReleaseMixin(project, input)
|
||||||
build.initialize_build_dir()
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def test(project):
|
def test(project):
|
||||||
run("pytest", check=True)
|
run("pytest", check=True)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def lint(project):
|
def lint(project):
|
||||||
run("flake8 --max-line-length=120 --count --select=E9,F63,F7,F82 "+
|
run(
|
||||||
"--show-source --statistics src/main/python/ddadevops/", shell=True, check=True)
|
"flake8 --max-line-length=120 --count --select=E9,F63,F7,F82 "
|
||||||
run("flake8 --count --exit-zero --max-complexity=10 --max-line-length=127 "+
|
+ "--show-source --statistics src/main/python/ddadevops/",
|
||||||
"--per-file-ignores=\"__init__.py:F401\" "+
|
shell=True,
|
||||||
"--ignore=E722,W503 --statistics src/main/python/ddadevops/", shell=True, check=True)
|
check=True,
|
||||||
run("python -m mypy src/main/python/ddadevops/ --ignore-missing-imports "+
|
)
|
||||||
"--disable-error-code=attr-defined --disable-error-code=union-attr", shell=True, check=True)
|
run(
|
||||||
run("pylint -d W0511,R0903,C0301,W0614,C0114,C0115,C0116,similarities,W1203,W0702,W0702,"+
|
"flake8 --count --exit-zero --max-complexity=10 --max-line-length=127 "
|
||||||
"R0913,R0902,R0914,R1732,R1705,W0707,C0123,W0703,C0103 src/main/python/ddadevops/", shell=True, check=True)
|
+ '--per-file-ignores="__init__.py:F401" '
|
||||||
|
+ "--ignore=E722,W503 --statistics src/main/python/ddadevops/",
|
||||||
|
shell=True,
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
run(
|
||||||
|
"python -m mypy src/main/python/ddadevops/ --ignore-missing-imports "
|
||||||
|
+ "--disable-error-code=attr-defined --disable-error-code=union-attr",
|
||||||
|
shell=True,
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def patch(project):
|
def patch(project):
|
||||||
build(project, "PATCH")
|
linttest(project, "PATCH")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def minor(project):
|
def minor(project):
|
||||||
build(project, "MINOR")
|
linttest(project, "MINOR")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def major(project):
|
def major(project):
|
||||||
build(project, "MAJOR")
|
linttest(project, "MAJOR")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def dev(project):
|
def dev(project):
|
||||||
build(project, "NONE")
|
linttest(project, "NONE")
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def nothing(project):
|
def prepare(project):
|
||||||
pass
|
|
||||||
|
|
||||||
@task
|
|
||||||
def prepare_release(project):
|
|
||||||
build = get_devops_build(project)
|
build = get_devops_build(project)
|
||||||
build.prepare_release()
|
build.prepare_release()
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def tag_bump_and_push_release(project):
|
def tag(project):
|
||||||
build = get_devops_build(project)
|
build = get_devops_build(project)
|
||||||
build.tag_bump_and_push_release()
|
build.tag_bump_and_push_release()
|
||||||
|
|
||||||
|
|
||||||
def build(project, release_type):
|
@task
|
||||||
|
def publish_artifacts(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.publish_artifacts()
|
||||||
|
|
||||||
|
|
||||||
|
def release(project):
|
||||||
|
prepare(project)
|
||||||
|
tag(project)
|
||||||
|
|
||||||
|
|
||||||
|
def linttest(project, release_type):
|
||||||
build = get_devops_build(project)
|
build = get_devops_build(project)
|
||||||
build.update_release_type(release_type)
|
build.update_release_type(release_type)
|
||||||
test(project)
|
test(project)
|
||||||
|
|
|
@ -35,7 +35,12 @@ classDiagram
|
||||||
| name | name in context of build & ENV | - | |
|
| name | name in context of build & ENV | - | |
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
### build.py
|
|
||||||
|
### Example project
|
||||||
|
|
||||||
|
A complete example project you can find on: https://repo.prod.meissa.de/meissa/buildtest
|
||||||
|
|
||||||
|
### Example of a build.py
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
|
@ -23,12 +23,9 @@ classDiagram
|
||||||
| build_dir_name | name of dir, build is executed in | target |
|
| build_dir_name | name of dir, build is executed in | target |
|
||||||
| build_types | list of special builds used. Valid values are ["IMAGE", "C4K", "K3S", "TERRAFORM"] | [] |
|
| build_types | list of special builds used. Valid values are ["IMAGE", "C4K", "K3S", "TERRAFORM"] | [] |
|
||||||
| mixin_types | mixins are orthoganl to builds and represent additional capabilities. Valid Values are ["RELEASE"] | [] |
|
| mixin_types | mixins are orthoganl to builds and represent additional capabilities. Valid Values are ["RELEASE"] | [] |
|
||||||
| module | module name - may result in a hierarchy like name/module | |
|
|
||||||
| name | dedicated name of the build | module |
|
|
||||||
| project_root_path | relative path to projects root. Is used to locate the target dir | |
|
|
||||||
| stage | sth. like test, int, acc or prod | |
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
### build.py
|
### build.py
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
|
@ -30,7 +30,7 @@ classDiagram
|
||||||
| image_dockerhub_user | user to access docker-hub | IMAGE_DOCKERHUB_USER from env or credentials from gopass |
|
| image_dockerhub_user | user to access docker-hub | IMAGE_DOCKERHUB_USER from env or credentials from gopass |
|
||||||
| image_dockerhub_password | password to access docker-hub | IMAGE_DOCKERHUB_PASSWORD from env or credentials from gopass |
|
| image_dockerhub_password | password to access docker-hub | IMAGE_DOCKERHUB_PASSWORD from env or credentials from gopass |
|
||||||
| image_tag | tag for publishing the image | IMAGE_TAG from env |
|
| image_tag | tag for publishing the image | IMAGE_TAG from env |
|
||||||
|
| image_naming | Strategy for calculate the image name. Posible values are [NAME_ONLY,NAME_AND_MODULE] |NAME_ONLY |
|
||||||
|
|
||||||
### Credentials Mapping defaults
|
### Credentials Mapping defaults
|
||||||
|
|
||||||
|
|
33
doc/Images.md
Normal file
33
doc/Images.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# ddadevops Images
|
||||||
|
## ddadevops-clojure
|
||||||
|
|
||||||
|
Contains
|
||||||
|
* clojure
|
||||||
|
* shadowcljs
|
||||||
|
* lein
|
||||||
|
* java
|
||||||
|
* graalvm
|
||||||
|
* pybuilder, ddadevops
|
||||||
|
|
||||||
|
## ddadevops
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
* pybuilder, ddadevops
|
||||||
|
|
||||||
|
## devops-build
|
||||||
|
|
||||||
|
Image is deprecated.
|
||||||
|
|
||||||
|
## ddadevops-dind
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
* docker in docker
|
||||||
|
* pybuilder, ddadevops
|
||||||
|
|
||||||
|
## ddadevops-python
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
* python 3.10
|
||||||
|
* python linting
|
||||||
|
* python setup-tools
|
||||||
|
* pybuilder, ddadevops
|
|
@ -14,13 +14,16 @@ classDiagram
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
| name | description | default |
|
| name | description | default |
|
||||||
| ----------------------------- | ----------------------------------------------------------------- | --------- |
|
| --------------------------------- | ----------------------------------------------------------------- | --------- |
|
||||||
| k3s_provision_user | the user used to provision k3s | "root" |
|
| k3s_provision_user | the user used to provision k3s | "root" |
|
||||||
| k3s_letsencrypt_email | email address used for letsencrypt | |
|
| k3s_letsencrypt_email | email address used for letsencrypt | |
|
||||||
| k3s_letsencrypt_endpoint | letsencrypt endpoint. Valid values are staging, prod | "staging" |
|
| k3s_letsencrypt_endpoint | letsencrypt endpoint. Valid values are staging, prod | "staging" |
|
||||||
| k3s_app_filename_to_provision | an k8s manifest to apply imediately after k3s setup was sucessful | |
|
| k3s_app_filename_to_provision | an k8s manifest to apply imediately after k3s setup was sucessful | |
|
||||||
| k3s_enable_echo | provision the echo app on k3s. Valid values are true, false | "false" |
|
| k3s_enable_echo | provision the echo app on k3s. Valid values are true, false | "false" |
|
||||||
| k3s_provs_template | use a individual template for provs config | None |
|
| k3s_provs_template | use a individual template for provs config | None |
|
||||||
|
| k3s_enable_hetzner_csi | enable hetzner csi | False |
|
||||||
|
| k3s_hetzner_api_token | hetzner_api_token | None |
|
||||||
|
| k3s_hetzner_encryption_passphrase | encryption passphrase for volumes | None |
|
||||||
|
|
||||||
### Credentials Mapping defaults
|
### Credentials Mapping defaults
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
# ReleaseMixin
|
# ReleaseMixin
|
||||||
|
|
||||||
|
- [ReleaseMixin](#releasemixin)
|
||||||
|
- [Input](#input)
|
||||||
|
- [Example Usage just for creating releases](#example-usage-just-for-creating-releases)
|
||||||
|
- [build.py](#buildpy)
|
||||||
|
- [call the build for creating a major release](#call-the-build-for-creating-a-major-release)
|
||||||
|
- [Example Usage for creating a release on forgejo / gitea \& upload the generated artifacts](#example-usage-for-creating-a-release-on-forgejo--gitea--upload-the-generated-artifacts)
|
||||||
|
- [build.py](#buildpy-1)
|
||||||
|
- [call the build](#call-the-build)
|
||||||
|
|
||||||
|
|
||||||
Support for releases following the trunk-based-release flow (see https://trunkbaseddevelopment.com/)
|
Support for releases following the trunk-based-release flow (see https://trunkbaseddevelopment.com/)
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
|
@ -8,6 +18,7 @@ classDiagram
|
||||||
prepare_release() - adjust all build files to carry the correct version & commit locally
|
prepare_release() - adjust all build files to carry the correct version & commit locally
|
||||||
tag_and_push_release() - tag the git repo and push changes to origin
|
tag_and_push_release() - tag the git repo and push changes to origin
|
||||||
update_release_type (release_type) - change the release type during run time
|
update_release_type (release_type) - change the release type during run time
|
||||||
|
publish_artifacts() - publish release & artifacts to forgejo/gitea
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -15,13 +26,103 @@ classDiagram
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
| name | description | default |
|
| name | description | default |
|
||||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------- |
|
| ----------------------------- |-----------------------------------------------------------------------------------------------------------------------| --------------- |
|
||||||
| release_type | one of MAJOR, MINOR, PATCH, NONE | "NONE" |
|
| release_type | one of MAJOR, MINOR, PATCH, NONE | "NONE" |
|
||||||
| release_main_branch | the name of your trank | "main" |
|
| release_main_branch | the name of your trunk | "main" |
|
||||||
| release_primary_build_file | path to the build file having the leading version info (read & write). Valid extensions are .clj, .json, .gradle, .py | "./project.clj" |
|
| release_primary_build_file | path to the build file having the leading version info (read & write). Valid extensions are .clj, .json, .gradle, .py | "./project.clj" |
|
||||||
| release_secondary_build_files | list of secondary build files, version is written in. | [] |
|
| release_secondary_build_files | list of secondary build files, version is written in. | [] |
|
||||||
|
| release_artifact_server_url | Optional: The base url of your forgejo/gitea instance to publish a release tode | |
|
||||||
|
| release_organisation | Optional: The repository organisation name | |
|
||||||
|
| release_repository_name | Optional: The repository name name | |
|
||||||
|
| release_artifacts | Optional: The list of artifacts to publish to the release generated name | [] |
|
||||||
|
| release_tag_prefix | Optional: Prefix of tag | "" |
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage just for creating releases
|
||||||
|
|
||||||
|
### build.py
|
||||||
|
|
||||||
|
```python
|
||||||
|
from os import environ
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
|
||||||
|
name = 'my-project'
|
||||||
|
MODULE = 'my-module'
|
||||||
|
PROJECT_ROOT_PATH = '..'
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
project.build_depends_on("ddadevops>=4.7.0")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": [],
|
||||||
|
"mixin_types": ["RELEASE"],
|
||||||
|
"release_type": "MINOR",
|
||||||
|
"release_primary_build_file": "project.clj",
|
||||||
|
"release_secondary_build_files": ["package.json"],
|
||||||
|
}
|
||||||
|
build = ReleaseMixin(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def patch(project):
|
||||||
|
linttest(project, "PATCH")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def minor(project):
|
||||||
|
linttest(project, "MINOR")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def major(project):
|
||||||
|
linttest(project, "MAJOR")
|
||||||
|
release(project)
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def dev(project):
|
||||||
|
linttest(project, "NONE")
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def prepare(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.prepare_release()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def tag(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.tag_bump_and_push_release()
|
||||||
|
|
||||||
|
|
||||||
|
def release(project):
|
||||||
|
prepare(project)
|
||||||
|
tag(project)
|
||||||
|
|
||||||
|
|
||||||
|
def linttest(project, release_type):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.update_release_type(release_type)
|
||||||
|
#test(project)
|
||||||
|
#lint(project)
|
||||||
|
```
|
||||||
|
|
||||||
|
### call the build for creating a major release
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pyb major
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Usage for creating a release on forgejo / gitea & upload the generated artifacts
|
||||||
|
|
||||||
### build.py
|
### build.py
|
||||||
|
|
||||||
|
@ -36,7 +137,7 @@ PROJECT_ROOT_PATH = '..'
|
||||||
|
|
||||||
@init
|
@init
|
||||||
def initialize(project):
|
def initialize(project):
|
||||||
project.build_depends_on("ddadevops>=4.0.0")
|
project.build_depends_on("ddadevops>=4.7.0")
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -48,35 +149,23 @@ def initialize(project):
|
||||||
"release_type": "MINOR",
|
"release_type": "MINOR",
|
||||||
"release_primary_build_file": "project.clj",
|
"release_primary_build_file": "project.clj",
|
||||||
"release_secondary_build_files": ["package.json"],
|
"release_secondary_build_files": ["package.json"],
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": "meissa",
|
||||||
|
"release_repository_name": "dda-devops-build",
|
||||||
|
"release_artifacts": ["target/doc.zip"],
|
||||||
}
|
}
|
||||||
|
|
||||||
roject.build_depends_on("ddadevops>=4.0.0-dev")
|
|
||||||
|
|
||||||
build = ReleaseMixin(project, input)
|
build = ReleaseMixin(project, input)
|
||||||
build.initialize_build_dir()
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def prepare_release(project):
|
def publish_artifacts(project):
|
||||||
build = get_devops_build(project)
|
build = get_devops_build(project)
|
||||||
build.prepare_release()
|
build.publish_artifacts()
|
||||||
|
|
||||||
@task
|
|
||||||
def build(project):
|
|
||||||
print("do the build")
|
|
||||||
|
|
||||||
@task
|
|
||||||
def publish(project):
|
|
||||||
print("publish your artefacts")
|
|
||||||
|
|
||||||
@task
|
|
||||||
def after_publish(project):
|
|
||||||
build = get_devops_build(project)
|
|
||||||
build.tag_bump_and_push_release()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### call the build
|
### call the build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pyb prepare_release build publish after_publish
|
git checkout "4.7.0"
|
||||||
|
pyb publish_artifacts
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,6 +12,7 @@ classDiagram
|
||||||
}
|
}
|
||||||
|
|
||||||
class Image {
|
class Image {
|
||||||
|
image_naming
|
||||||
image_dockerhub_user
|
image_dockerhub_user
|
||||||
image_dockerhub_password
|
image_dockerhub_password
|
||||||
image_publish_tag
|
image_publish_tag
|
||||||
|
@ -87,6 +88,15 @@ classDiagram
|
||||||
release_type
|
release_type
|
||||||
release_main_branch
|
release_main_branch
|
||||||
release_current_branch
|
release_current_branch
|
||||||
|
release_artifact_server_url
|
||||||
|
release_organisation
|
||||||
|
release_repository_name
|
||||||
|
release_artifact_token
|
||||||
|
}
|
||||||
|
class Artifact {
|
||||||
|
path_str
|
||||||
|
path()
|
||||||
|
type()
|
||||||
}
|
}
|
||||||
class Credentials {
|
class Credentials {
|
||||||
<<AggregateRoot>>
|
<<AggregateRoot>>
|
||||||
|
@ -129,6 +139,7 @@ classDiagram
|
||||||
TerraformDomain *-- "0..1" ProviderAws: providers
|
TerraformDomain *-- "0..1" ProviderAws: providers
|
||||||
Release o-- "0..1" BuildFile: primary_build_file
|
Release o-- "0..1" BuildFile: primary_build_file
|
||||||
Release o-- "0..n" BuildFile: secondary_build_files
|
Release o-- "0..n" BuildFile: secondary_build_files
|
||||||
|
Release "1" *-- "0..n" Artifact: release_artifacts
|
||||||
Release "1" *-- "1" Version: version
|
Release "1" *-- "1" Version: version
|
||||||
BuildFile *-- "1" Version: version
|
BuildFile *-- "1" Version: version
|
||||||
C4k *-- DnsRecord: dns_record
|
C4k *-- DnsRecord: dns_record
|
||||||
|
|
|
@ -16,35 +16,85 @@ We discussed how we will handle releases in cooperation with gitlab-ci.
|
||||||
|
|
||||||
### Outcome of Eventstroming: Events ordered by time
|
### Outcome of Eventstroming: Events ordered by time
|
||||||
|
|
||||||
1. B: Pulls the latest changes
|
* B: is the human devops
|
||||||
1. B: Possibly merge/rebase with main
|
* S: is the build / ci system
|
||||||
1.
|
|
||||||
1. B: starts "create release-notes"
|
```mermaid
|
||||||
1. B: commits his changes with [skip-ci].
|
stateDiagram-v2
|
||||||
1.
|
state prepare_release {
|
||||||
1. B: starts the release build and specifies major, minor, patch
|
state "B: Pulls the latest changes" as pull
|
||||||
1.
|
state "B: Possibly merge/rebase with main" as merge
|
||||||
1. S: does a git fetch & status and checks if there are no changes at origin
|
state "B: starts 'create release-notes'" as rn
|
||||||
1. S: starts tests
|
state "B: commits his changes with [skip-ci]." as c1
|
||||||
1. S: runs the linting
|
|
||||||
1. S: possibly does image building and image testing
|
[*] --> pull
|
||||||
1.
|
pull --> merge
|
||||||
1. S: version numbers are adjusted in project.clj/package.json to full version
|
merge --> rn
|
||||||
1. S: change commit is tagged with git tag
|
rn --> c1
|
||||||
1. S: version numbers are adjusted in project.clj/package.json to next snapshot version
|
c1 --> [*]
|
||||||
1. S: makes a bump commit with [skip-ci].
|
}
|
||||||
1. S: push to gitlab/gitea along with git tags
|
state release {
|
||||||
1.
|
state "B: starts the release build and specifies major, minor, patch" as trigger
|
||||||
1. S: CI starts - for a new tag
|
state "S: does a git fetch & status and checks if there are no changes at origin" as fetch
|
||||||
1. S: CI runs tests
|
state "S: starts tests" as test
|
||||||
1. S: runs the linting
|
state "S: runs the linting" as lint
|
||||||
1. S: makes artifacts
|
state "S: possibly does image building and image testing" as image
|
||||||
1. S: possibly performs image building and image testing
|
state "S: version numbers are adjusted in project.clj/package.json to full version" as vno
|
||||||
1. S: publishes images and artifacts
|
state "S: change commit is tagged with git tag" as c2
|
||||||
1.
|
state "S: version numbers are adjusted in project.clj/package.json to next snapshot " as snap
|
||||||
1. S: CI starts - for push with the last commit
|
state "S: makes a bump commit with [skip-ci]." as c3
|
||||||
1. S: CI runs tests
|
state "S: push to gitlab/gitea along with git tags" as push
|
||||||
1. S: performs the linting
|
|
||||||
|
[*] --> trigger
|
||||||
|
trigger --> fetch
|
||||||
|
fetch --> lint
|
||||||
|
fetch --> test
|
||||||
|
fetch --> image
|
||||||
|
test --> vno
|
||||||
|
lint --> vno
|
||||||
|
image --> vno
|
||||||
|
vno --> c2
|
||||||
|
c2 --> snap
|
||||||
|
snap --> c3
|
||||||
|
c3 --> push
|
||||||
|
push --> [*]
|
||||||
|
}
|
||||||
|
state ci_tag {
|
||||||
|
state "S: CI starts - for a new tag" as ct1
|
||||||
|
state "S: runs the linting" as ct2
|
||||||
|
state "S: CI runs tests" as ct3
|
||||||
|
state "S: makes artifacts" as ct4
|
||||||
|
state "S: possibly performs image building and image testing" as ct5
|
||||||
|
state "S: publishes images and artifacts" as ct6
|
||||||
|
|
||||||
|
|
||||||
|
[*] --> ct1
|
||||||
|
ct1 --> ct2
|
||||||
|
ct2 --> ct3
|
||||||
|
ct3 --> ct4
|
||||||
|
ct4 --> ct5
|
||||||
|
ct5 --> ct6
|
||||||
|
ct6 --> [*]
|
||||||
|
}
|
||||||
|
state ci_version_bump {
|
||||||
|
state "S: CI starts - for push with the last commit" as cvb1
|
||||||
|
state "S: CI runs tests" as cvb2
|
||||||
|
state "S: performs the linting" as cvb3
|
||||||
|
|
||||||
|
[*] --> cvb1
|
||||||
|
cvb1 --> cvb2
|
||||||
|
cvb2 --> cvb3
|
||||||
|
cvb3 --> [*]
|
||||||
|
}
|
||||||
|
|
||||||
|
[*] --> prepare_release
|
||||||
|
prepare_release --> release
|
||||||
|
release --> ci_tag
|
||||||
|
release --> ci_version_bump
|
||||||
|
ci_tag --> [*]
|
||||||
|
ci_version_bump --> [*]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
adjust version no in build.py to release version no.
|
|
||||||
git commit -am "release"
|
|
||||||
git tag -am "release" [release version no]
|
|
||||||
git push --follow-tags
|
|
||||||
increase version no in build.py
|
|
||||||
git commit -am "version bump"
|
|
||||||
git push
|
|
||||||
pip3 install --upgrade ddadevops
|
|
56
infrastructure/backup/build.py
Normal file
56
infrastructure/backup/build.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
import logging
|
||||||
|
|
||||||
|
name = 'dda-backup'
|
||||||
|
MODULE = 'NOT_SET'
|
||||||
|
PROJECT_ROOT_PATH = '../..'
|
||||||
|
version = "4.12.2-dev"
|
||||||
|
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": ["IMAGE"],
|
||||||
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_ONLY",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build_depends_on("ddadevops>=4.7.0")
|
||||||
|
|
||||||
|
build = DevopsImageBuild(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def image(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.image()
|
||||||
|
|
||||||
|
@task
|
||||||
|
def test(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.test()
|
||||||
|
|
||||||
|
@task
|
||||||
|
def drun(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.drun()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def publish(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.dockerhub_login()
|
||||||
|
build.dockerhub_publish()
|
79
infrastructure/backup/doc/backup_dev_notes.md
Normal file
79
infrastructure/backup/doc/backup_dev_notes.md
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
## Init Statemachine
|
||||||
|
|
||||||
|
### Inputs
|
||||||
|
1. `restic-password: ""`
|
||||||
|
2. `restic-password-to-rotate: ""`
|
||||||
|
|
||||||
|
### Manual init the restic repository for the first time
|
||||||
|
|
||||||
|
1. apply backup-and-restore pod:
|
||||||
|
`kubectl scale deployment backup-restore --replicas=1`
|
||||||
|
2. exec into pod and execute restore pod (press tab to get your exact pod name)
|
||||||
|
`kubectl exec -it backup-restore-... -- /usr/local/bin/init.sh`
|
||||||
|
3. remove backup-and-restore pod:
|
||||||
|
`kubectl scale deployment backup-restore --replicas=0`
|
||||||
|
|
||||||
|
### Password Rotation
|
||||||
|
|
||||||
|
1. apply backup-and-restore pod:
|
||||||
|
`kubectl scale deployment backup-restore --replicas=1`
|
||||||
|
2. add new password to restic repository
|
||||||
|
`restic key add ....`
|
||||||
|
=> Trigger ::
|
||||||
|
field (1) credential current
|
||||||
|
filed (2) credential new
|
||||||
|
3. replace field (1) with (2) & clear (2)
|
||||||
|
4. remove old key - ???
|
||||||
|
`restic remove ....`
|
||||||
|
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> init
|
||||||
|
init --> backup_ready: trigger, restic-password !empty
|
||||||
|
backup_ready --> new_password_added: restic-password !empty && restic-password-to-rotate !empty
|
||||||
|
new_password_added --> backup_ready: restic-password !empty && restic-password-to-rotate empty
|
||||||
|
```
|
||||||
|
|
||||||
|
### First Steps
|
||||||
|
|
||||||
|
1. Cloud Testserver hochfahren
|
||||||
|
2. Dort backup-restore deployment (leeres Secret mgl.?), neues Secret "rotation-credential-secret" als Daten
|
||||||
|
3. mounten von angelegtem Secret in Pod backup-restore
|
||||||
|
4. ba*bash*ka Skript in pod starten -> liest Secret ?leer
|
||||||
|
5. Micha cons.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant k8s
|
||||||
|
participant e as entrypoint.sh
|
||||||
|
participant rm as restic-management.clj
|
||||||
|
|
||||||
|
k8s ->> e: cronjob calls
|
||||||
|
e ->> rm: start-file
|
||||||
|
rm ->> rm: rotate
|
||||||
|
activate rm
|
||||||
|
rm ->> rm: read-backup-repository-state (state)
|
||||||
|
rm ->> rm: read-secret (backup-secret/restic-password, rotation-credential-secret/rotation-credential)
|
||||||
|
rm ->> rm: switch
|
||||||
|
activate rm
|
||||||
|
rm ->> rm: if init && restic-password != null
|
||||||
|
activate rm
|
||||||
|
rm ->> rm: init.sh
|
||||||
|
rm ->> rm: state init -> backup-ready
|
||||||
|
deactivate rm
|
||||||
|
rm ->> rm: if backup-ready && rotation-credential != null
|
||||||
|
activate rm
|
||||||
|
rm ->> rm: add-new-password-to-restic-repository.sh
|
||||||
|
rm ->> rm: state backup-ready -> new-password-added
|
||||||
|
deactivate rm
|
||||||
|
rm ->> rm: if new-password-added && rotation-credential == null
|
||||||
|
activate rm
|
||||||
|
rm ->> rm: remove-old-password-from-restic-repository.sh
|
||||||
|
rm ->> rm: state new-password-added -> backup-ready
|
||||||
|
deactivate rm
|
||||||
|
deactivate rm
|
||||||
|
|
||||||
|
rm ->> rm: store-repository-state (state)
|
||||||
|
deactivate rm
|
||||||
|
```
|
5
infrastructure/backup/image/Dockerfile
Normal file
5
infrastructure/backup/image/Dockerfile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
FROM ubuntu:jammy
|
||||||
|
|
||||||
|
# install it
|
||||||
|
ADD resources /tmp/
|
||||||
|
RUN /tmp/install.sh
|
70
infrastructure/backup/image/resources/file-functions.sh
Normal file
70
infrastructure/backup/image/resources/file-functions.sh
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
backup_file_path='files'
|
||||||
|
|
||||||
|
function init-file-repo() {
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} -v init
|
||||||
|
else
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} -v init --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# First arg is the directory, second is optional for the path to a certificate file
|
||||||
|
function backup-directory() {
|
||||||
|
local directory="$1"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache
|
||||||
|
cd ${directory} && restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} backup .
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune
|
||||||
|
else
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache --cacert ${CERTIFICATE_FILE}
|
||||||
|
cd ${directory} && restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} backup . --cacert ${CERTIFICATE_FILE}
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# First arg is the directory, the remaining args are the sub-directories (relative to the first directory) to backup.
|
||||||
|
function backup-fs-from-directory() {
|
||||||
|
local directory="$1"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache
|
||||||
|
cd ${directory} && restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} backup $@
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune
|
||||||
|
else
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache --cacert ${CERTIFICATE_FILE}
|
||||||
|
cd ${directory} && restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} backup $@ --cacert ${CERTIFICATE_FILE}
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Das tut so nicht!
|
||||||
|
function restore-directory() {
|
||||||
|
local directory="$1"; shift
|
||||||
|
local snapshot_id="${1:-latest}"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache
|
||||||
|
rm -rf ${directory}*
|
||||||
|
restic -v -r $RESTIC_REPOSITORY/${backup_file_path} restore ${snapshot_id} --target ${directory}
|
||||||
|
else
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_file_path} unlock --cleanup-cache --cacert ${CERTIFICATE_FILE}
|
||||||
|
rm -rf ${directory}*
|
||||||
|
restic -v -r $RESTIC_REPOSITORY/${backup_file_path} restore ${snapshot_id} --target ${directory} --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function list-snapshot-files() {
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} snapshots
|
||||||
|
else
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} snapshots --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
21
infrastructure/backup/image/resources/functions.sh
Normal file
21
infrastructure/backup/image/resources/functions.sh
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# usage: file_env VAR [DEFAULT]
|
||||||
|
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
||||||
|
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
||||||
|
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
||||||
|
function file_env() {
|
||||||
|
local var="$1"
|
||||||
|
local fileVar="${var}_FILE"
|
||||||
|
local def="${2:-}"
|
||||||
|
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
||||||
|
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
local val="$def"
|
||||||
|
if [ "${!var:-}" ]; then
|
||||||
|
val="${!var}"
|
||||||
|
elif [ "${!fileVar:-}" ]; then
|
||||||
|
val="$(< "${!fileVar}")"
|
||||||
|
fi
|
||||||
|
export "$var"="$val"
|
||||||
|
unset "$fileVar"
|
||||||
|
}
|
36
infrastructure/backup/image/resources/install.sh
Executable file
36
infrastructure/backup/image/resources/install.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function babashka_install() {
|
||||||
|
babashka_version="1.3.189"
|
||||||
|
curl -SsLo /tmp/babashka-${babashka_version}-linux-amd64.tar.gz https://github.com/babashka/babashka/releases/download/v${babashka_version}/babashka-${babashka_version}-linux-amd64.tar.gz
|
||||||
|
curl -SsLo /tmp/checksum https://github.com/babashka/babashka/releases/download/v${babashka_version}/babashka-${babashka_version}-linux-amd64.tar.gz.sha256
|
||||||
|
echo " /tmp/babashka-$babashka_version-linux-amd64.tar.gz"|tee -a /tmp/checksum
|
||||||
|
sha256sum -c --status /tmp/checksum
|
||||||
|
tar -C /tmp -xzf /tmp/babashka-${babashka_version}-linux-amd64.tar.gz
|
||||||
|
install -m 0700 -o root -g root /tmp/bb /usr/local/bin/
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
apt-get install -qqy ca-certificates curl gnupg postgresql-client-14 restic
|
||||||
|
curl -Ss --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/postgresql-common_pgdg_archive_keyring.gpg
|
||||||
|
sh -c 'echo "deb [signed-by=/etc/apt/trusted.gpg.d/postgresql-common_pgdg_archive_keyring.gpg] https://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||||
|
upgradeSystem
|
||||||
|
babashka_install
|
||||||
|
} > /dev/null
|
||||||
|
|
||||||
|
update-ca-certificates
|
||||||
|
|
||||||
|
install -m 0400 /tmp/functions.sh /usr/local/lib/
|
||||||
|
install -m 0400 /tmp/pg-functions.sh /usr/local/lib/
|
||||||
|
install -m 0400 /tmp/file-functions.sh /usr/local/lib/
|
||||||
|
install -m 0740 /tmp/restic_management.clj /usr/local/bin/
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_debian.sh
|
||||||
|
DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes main
|
149
infrastructure/backup/image/resources/pg-functions.sh
Normal file
149
infrastructure/backup/image/resources/pg-functions.sh
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
backup_pg_role_path='pg-role'
|
||||||
|
backup_pg_database_path='pg-database'
|
||||||
|
|
||||||
|
function init-command() {
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} -v init $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function init-role-repo() {
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
init-command
|
||||||
|
else
|
||||||
|
init-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function init-database-command() {
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} -v init $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function init-database-repo() {
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
init-database-command
|
||||||
|
else
|
||||||
|
init-database-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function drop-create-db() {
|
||||||
|
psql -d template1 -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password -c "DROP DATABASE \"${POSTGRES_DB}\";"
|
||||||
|
psql -d template1 -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password -c "CREATE DATABASE \"${POSTGRES_DB}\";"
|
||||||
|
}
|
||||||
|
|
||||||
|
function create-pg-pass() {
|
||||||
|
local pg_host=${POSTGRES_HOST:-localhost}
|
||||||
|
|
||||||
|
echo "${pg_host}:${POSTGRES_DB}:${POSTGRES_USER}:${POSTGRES_PASSWORD}" > /root/.pgpass
|
||||||
|
echo "${POSTGRES_HOST}:template1:${POSTGRES_USER}:${POSTGRES_PASSWORD}" >> /root/.pgpass
|
||||||
|
chmod 0600 /root/.pgpass
|
||||||
|
}
|
||||||
|
|
||||||
|
function roles-unlock-command() {
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} unlock --cleanup-cache $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function roles-forget-command() {
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function backup-roles() {
|
||||||
|
local role_prefix="$1"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
roles-unlock-command
|
||||||
|
pg_dumpall -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U${POSTGRES_USER} --no-password --roles-only | \
|
||||||
|
grep ${role_prefix} | restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} backup --stdin
|
||||||
|
roles-forget-command
|
||||||
|
else
|
||||||
|
roles-unlock-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
pg_dumpall -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U${POSTGRES_USER} --no-password --roles-only | \
|
||||||
|
grep ${role_prefix} | restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} backup --stdin --cacert ${CERTIFICATE_FILE}
|
||||||
|
roles-forget-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function db-unlock-command() {
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} unlock --cleanup-cache $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function db-forget-command() {
|
||||||
|
restic -v -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} forget --group-by '' --keep-last 1 --keep-daily ${RESTIC_DAYS_TO_KEEP} --keep-monthly ${RESTIC_MONTHS_TO_KEEP} --prune $@
|
||||||
|
}
|
||||||
|
|
||||||
|
function backup-db-dump() {
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
db-unlock-command
|
||||||
|
pg_dump -d ${POSTGRES_DB} -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} \
|
||||||
|
-U ${POSTGRES_USER} --no-password --serializable-deferrable | \
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} backup --stdin
|
||||||
|
db-forget-command
|
||||||
|
else
|
||||||
|
db-unlock-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
pg_dump -d ${POSTGRES_DB} -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} \
|
||||||
|
-U ${POSTGRES_USER} --no-password --serializable-deferrable | \
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} backup --stdin --cacert ${CERTIFICATE_FILE}
|
||||||
|
db-forget-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore-roles() {
|
||||||
|
local snapshot_id="${1:-latest}"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
roles-unlock-command
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} dump ${snapshot_id} stdin | \
|
||||||
|
psql -d template1 -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password
|
||||||
|
else
|
||||||
|
roles-unlock-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} dump ${snapshot_id} stdin --cacert ${CERTIFICATE_FILE} | \
|
||||||
|
psql -d template1 -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore-db() {
|
||||||
|
local snapshot_id="${1:-latest}"; shift
|
||||||
|
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
db-unlock-command
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} dump ${snapshot_id} stdin | \
|
||||||
|
psql -d ${POSTGRES_DB} -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password
|
||||||
|
else
|
||||||
|
db-unlock-command --cacert ${CERTIFICATE_FILE}
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} dump ${snapshot_id} stdin --cacert ${CERTIFICATE_FILE} | \
|
||||||
|
psql -d ${POSTGRES_DB} -h ${POSTGRES_SERVICE} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} \
|
||||||
|
--no-password
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function list-snapshot-roles() {
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_role_path} snapshots
|
||||||
|
else
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} snapshots --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function list-snapshot-db() {
|
||||||
|
if [ -z ${CERTIFICATE_FILE} ];
|
||||||
|
then
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} snapshots
|
||||||
|
else
|
||||||
|
restic -r ${RESTIC_REPOSITORY}/${backup_pg_database_path} snapshots --cacert ${CERTIFICATE_FILE}
|
||||||
|
fi
|
||||||
|
}
|
51
infrastructure/backup/image/resources/restic_management.clj
Executable file
51
infrastructure/backup/image/resources/restic_management.clj
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
#! /usr/bin/env bb
|
||||||
|
|
||||||
|
(ns restic-management
|
||||||
|
(:require
|
||||||
|
[clojure.spec.alpha :as s]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[clojure.edn :as edn]))
|
||||||
|
|
||||||
|
(s/def ::state string?)
|
||||||
|
|
||||||
|
(s/def ::backup-repository-state
|
||||||
|
(s/keys :req-un [::state]))
|
||||||
|
|
||||||
|
(def state {:state ""})
|
||||||
|
|
||||||
|
(defn store-backup-repository-state [s]
|
||||||
|
(spit "backup-repository-state.edn" s))
|
||||||
|
|
||||||
|
(defn read-backup-repository-state []
|
||||||
|
(try
|
||||||
|
(with-open [r (io/reader "backup-repository-state.edn")]
|
||||||
|
(edn/read (java.io.PushbackReader. r)))
|
||||||
|
|
||||||
|
(catch java.io.IOException e
|
||||||
|
(printf "Couldn't open '%s': %s\n" "backup-repository-state.edn" (.getMessage e)))
|
||||||
|
(catch RuntimeException e
|
||||||
|
(printf "Error parsing edn file '%s': %s\n" "backup-repository-state.edn" (.getMessage e)))))
|
||||||
|
|
||||||
|
(defn read-secret [s]
|
||||||
|
(slurp (str "/var/run/secrets/" s)))
|
||||||
|
;"/var/run/secrets/rotation-credential-secret/rotation-credential"))
|
||||||
|
|
||||||
|
;(println (read-backup-repository-state))
|
||||||
|
|
||||||
|
;(println (:state (read-backup-repository-state)))
|
||||||
|
|
||||||
|
;(println (s/valid? ::backup-repository-state (read-backup-repository-state)))
|
||||||
|
|
||||||
|
(println (read-secret "rotation-credential-secret/rotation-credential"))
|
||||||
|
(println (read-secret "backup-secrets/restic-password"))
|
||||||
|
|
||||||
|
(s/def ::new-password string?)
|
||||||
|
(s/def ::old-password string?)
|
||||||
|
(s/def ::password-state
|
||||||
|
(s/keys :req-un [::new-password ::old-password]))
|
||||||
|
|
||||||
|
(defn rotate []
|
||||||
|
(let [state {:new-password (read-secret "rotation-credential-secret/rotation-credential")
|
||||||
|
:old-password (read-secret "backup-secrets/restic-password")}]
|
||||||
|
(store-backup-repository-state (prn-str state))))
|
||||||
|
(rotate)
|
7
infrastructure/backup/test/Dockerfile
Normal file
7
infrastructure/backup/test/Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FROM dda-backup:latest
|
||||||
|
|
||||||
|
# install it
|
||||||
|
RUN apt update && apt install -qqy openjdk-17-jre-headless
|
||||||
|
ADD resources /tmp/
|
||||||
|
RUN rm -rf /root/.m2
|
||||||
|
RUN /tmp/install-test.bb
|
4
infrastructure/backup/test/resources/bb.edn
Normal file
4
infrastructure/backup/test/resources/bb.edn
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
|
||||||
|
orchestra/orchestra {:mvn/version "2021.01.01-1"}
|
||||||
|
org.domaindrivenarchitecture/dda-backup {:mvn/version "0.1.1-SNAPSHOT"}}}
|
||||||
|
|
32
infrastructure/backup/test/resources/install-test.bb
Executable file
32
infrastructure/backup/test/resources/install-test.bb
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env bb
|
||||||
|
|
||||||
|
(require '[babashka.tasks :as tasks])
|
||||||
|
|
||||||
|
(defn curl-and-check!
|
||||||
|
[filename artifact-url sha256-url]
|
||||||
|
(let [filepath (str "/tmp/" filename)]
|
||||||
|
(tasks/shell "curl" "-SsLo" filepath artifact-url)
|
||||||
|
(tasks/shell "curl" "-SsLo" "/tmp/checksum" sha256-url)
|
||||||
|
(tasks/shell "bash" "-c" (str "echo \" " filepath "\"|tee -a /tmp/checksum"))
|
||||||
|
;(tasks/shell "sha256sum" "-c" "--status" "/tmp/checksum")
|
||||||
|
))
|
||||||
|
|
||||||
|
(defn tar-install!
|
||||||
|
[filename binname]
|
||||||
|
(let [filepath (str "/tmp/" filename)]
|
||||||
|
(tasks/shell "tar" "-C" "/tmp" "-xzf" filepath)
|
||||||
|
(tasks/shell "install" "-m" "0700" "-o" "root" "-g" "root" (str "/tmp/" binname) "/usr/local/bin/")))
|
||||||
|
|
||||||
|
(defn install!
|
||||||
|
[filename]
|
||||||
|
(tasks/shell "install" "-m" "0700" "-o" "root" "-g" "root" (str "/tmp/" filename) "/usr/local/bin/"))
|
||||||
|
|
||||||
|
(tasks/shell "bb" "/tmp/test.bb")
|
||||||
|
(curl-and-check!
|
||||||
|
"provs-syspec.jar"
|
||||||
|
"https://repo.prod.meissa.de/attachments/0a1da41e-aa5b-4a3e-a3b1-215cf2d5b021"
|
||||||
|
"https://repo.prod.meissa.de/attachments/f227cf65-cb0f-46a7-a6cd-28f46917412a")
|
||||||
|
(install! "provs-syspec.jar")
|
||||||
|
(tasks/shell "apt" "update")
|
||||||
|
(tasks/shell "apt" "install" "-qqy" "openjdk-17-jre-headless")
|
||||||
|
(tasks/shell "java" "-jar" "/usr/local/bin/provs-syspec.jar" "local" "-c" "/tmp/spec.yml" )
|
7
infrastructure/backup/test/resources/spec.yml
Normal file
7
infrastructure/backup/test/resources/spec.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package:
|
||||||
|
- name: "restic"
|
||||||
|
|
||||||
|
command:
|
||||||
|
- command: "bb -h"
|
||||||
|
- command: "/tmp/test.bb"
|
||||||
|
|
27
infrastructure/backup/test/resources/test.bb
Executable file
27
infrastructure/backup/test/resources/test.bb
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bb
|
||||||
|
|
||||||
|
(require '[babashka.tasks :as tasks]
|
||||||
|
'[dda.backup.management :as mgm])
|
||||||
|
|
||||||
|
(defn restic-repo-init!
|
||||||
|
[]
|
||||||
|
(spit "restic-pwd" "ThePassword")
|
||||||
|
(mgm/init! {:password-file "restic-pwd"
|
||||||
|
:restic-repository "restic-repo"}))
|
||||||
|
|
||||||
|
(defn restic-backup!
|
||||||
|
[]
|
||||||
|
(tasks/shell "mkdir" "test-backup")
|
||||||
|
(spit "test-backup/file" "I was here")
|
||||||
|
(tasks/shell "restic" "backup" "--password-file" "restic-pwd" "--repo" "restic-repo" "test-backup"))
|
||||||
|
|
||||||
|
(defn restic-restore!
|
||||||
|
[]
|
||||||
|
(tasks/shell "mkdir" "test-restore")
|
||||||
|
(tasks/shell "restic" "restore" "--password-file" "restic-pwd" "--repo" "restic-repo" "--target" "test-restore" "latest")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(restic-repo-init!)
|
||||||
|
(restic-backup!)
|
||||||
|
(restic-restore!)
|
56
infrastructure/clj-cljs/build.py
Normal file
56
infrastructure/clj-cljs/build.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
|
||||||
|
name = "ddadevops"
|
||||||
|
MODULE = "clj-cljs"
|
||||||
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": ["IMAGE"],
|
||||||
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_AND_MODULE",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build_depends_on("ddadevops>=4.0.0")
|
||||||
|
|
||||||
|
build = DevopsImageBuild(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def image(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.image()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def drun(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.drun()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def test(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.test()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def publish(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.dockerhub_login()
|
||||||
|
build.dockerhub_publish()
|
4
infrastructure/clj-cljs/image/Dockerfile
Normal file
4
infrastructure/clj-cljs/image/Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
FROM node:lts-bookworm-slim
|
||||||
|
|
||||||
|
ADD resources /tmp
|
||||||
|
RUN /tmp/install.sh
|
45
infrastructure/clj-cljs/image/resources/install.sh
Executable file
45
infrastructure/clj-cljs/image/resources/install.sh
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
mkdir -p /usr/share/man/man1
|
||||||
|
apt-get -qqy install curl openjdk-17-jre-headless leiningen
|
||||||
|
|
||||||
|
# shadow-cljs
|
||||||
|
npm install -g npm
|
||||||
|
npm install -g --save-dev shadow-cljs
|
||||||
|
|
||||||
|
# download kubeconform & graalvm
|
||||||
|
kubeconform_version="0.6.4"
|
||||||
|
|
||||||
|
curl -SsLo /tmp/kubeconform-linux-amd64.tar.gz https://github.com/yannh/kubeconform/releases/download/v${kubeconform_version}/kubeconform-linux-amd64.tar.gz
|
||||||
|
curl -SsLo /tmp/CHECKSUMS https://github.com/yannh/kubeconform/releases/download/v${kubeconform_version}/CHECKSUMS
|
||||||
|
|
||||||
|
# checksum kubeconform
|
||||||
|
checksum
|
||||||
|
|
||||||
|
# install kubeconform
|
||||||
|
tar -C /usr/local/bin -xf /tmp/kubeconform-linux-amd64.tar.gz --exclude=LICENSE
|
||||||
|
|
||||||
|
#install pyb
|
||||||
|
apt-get -qqy install python3 python3-pip git
|
||||||
|
pip3 install pybuilder 'ddadevops>=4.7.0' deprecation dda-python-terraform boto3 pyyaml inflection --break-system-packages
|
||||||
|
|
||||||
|
#check
|
||||||
|
lein --help
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksum() {
|
||||||
|
awk '{print $1 " /tmp/" $2}' /tmp/CHECKSUMS|sed -n '2p' > /tmp/kubeconform-checksum
|
||||||
|
cat /tmp/kubeconform-checksum
|
||||||
|
sha256sum -c --status /tmp/kubeconform-checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_debian.sh
|
||||||
|
DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes main
|
|
@ -1,14 +1,18 @@
|
||||||
from os import environ
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
from pybuilder.core import task, init
|
from pybuilder.core import task, init
|
||||||
from ddadevops import *
|
from ddadevops import *
|
||||||
|
|
||||||
name = "clojure"
|
name = "ddadevops"
|
||||||
MODULE = "image"
|
MODULE = "clj"
|
||||||
PROJECT_ROOT_PATH = "../.."
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
@init
|
@init
|
||||||
def initialize(project):
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -17,6 +21,8 @@ def initialize(project):
|
||||||
"project_root_path": PROJECT_ROOT_PATH,
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
"build_types": ["IMAGE"],
|
"build_types": ["IMAGE"],
|
||||||
"mixin_types": [],
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_AND_MODULE",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
}
|
}
|
||||||
|
|
||||||
project.build_depends_on("ddadevops>=4.0.0")
|
project.build_depends_on("ddadevops>=4.0.0")
|
6
infrastructure/clj/image/Dockerfile
Normal file
6
infrastructure/clj/image/Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
FROM debian:stable-slim
|
||||||
|
|
||||||
|
ADD resources /tmp
|
||||||
|
RUN /tmp/install.sh
|
||||||
|
ENV LANG=en_US.UTF-8 \
|
||||||
|
JAVA_HOME=/usr/lib/jvm/graalvm
|
57
infrastructure/clj/image/resources/install.sh
Executable file
57
infrastructure/clj/image/resources/install.sh
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
apt-get -qqy install curl git openjdk-17-jre-headless leiningen build-essential libz-dev zlib1g-dev
|
||||||
|
|
||||||
|
|
||||||
|
# download kubeconform & graalvm
|
||||||
|
kubeconform_version="0.6.4"
|
||||||
|
graalvm_jdk_version="21.0.2"
|
||||||
|
|
||||||
|
curl -SsLo /tmp/kubeconform-linux-amd64.tar.gz https://github.com/yannh/kubeconform/releases/download/v${kubeconform_version}/kubeconform-linux-amd64.tar.gz
|
||||||
|
curl -SsLo /tmp/CHECKSUMS https://github.com/yannh/kubeconform/releases/download/v${kubeconform_version}/CHECKSUMS
|
||||||
|
curl -SsLo /tmp/graalvm-community-jdk.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${graalvm_jdk_version}/graalvm-community-jdk-${graalvm_jdk_version}_linux-x64_bin.tar.gz
|
||||||
|
curl -SsLo /tmp/graalvm-checksum https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-${graalvm_jdk_version}/graalvm-community-jdk-${graalvm_jdk_version}_linux-x64_bin.tar.gz.sha256
|
||||||
|
|
||||||
|
# checksum kubeconform & graalvm-jdk
|
||||||
|
checksum
|
||||||
|
|
||||||
|
# install kubeconform
|
||||||
|
tar -C /usr/local/bin -xf /tmp/kubeconform-linux-amd64.tar.gz --exclude=LICENSE
|
||||||
|
|
||||||
|
# install graalvm
|
||||||
|
tar -C /usr/lib/jvm/ -xf /tmp/graalvm-community-jdk.tar.gz
|
||||||
|
dirname_graalvm=$(ls /usr/lib/jvm/|grep -e graa)
|
||||||
|
ln -s /usr/lib/jvm/$dirname_graalvm /usr/lib/jvm/graalvm
|
||||||
|
ln -s /usr/lib/jvm/graalvm/bin/gu /usr/local/bin
|
||||||
|
update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm/bin/java 2
|
||||||
|
ln -s /usr/lib/jvm/graalvm/bin/native-image /usr/local/bin
|
||||||
|
|
||||||
|
#install pyb
|
||||||
|
apt-get -qqy install python3 python3-pip
|
||||||
|
pip3 install pybuilder 'ddadevops>=4.7.0' deprecation dda-python-terraform boto3 pyyaml inflection --break-system-packages
|
||||||
|
|
||||||
|
#check
|
||||||
|
native-image --version
|
||||||
|
lein -v
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksum() {
|
||||||
|
#kubeconform
|
||||||
|
awk '{print $1 " /tmp/" $2}' /tmp/CHECKSUMS|sed -n '2p' > /tmp/kubeconform-checksum
|
||||||
|
sha256sum -c --status /tmp/kubeconform-checksum
|
||||||
|
|
||||||
|
#graalvm
|
||||||
|
echo " /tmp/graalvm-community-jdk.tar.gz"|tee -a /tmp/graalvm-checksum
|
||||||
|
sha256sum -c --status /tmp/graalvm-checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_debian.sh
|
||||||
|
DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes main
|
|
@ -1,2 +0,0 @@
|
||||||
d7a5cb848b783c15119316d716d8a74bf11c9e3ab050f3adf28e0678a6018467 kubeconform-v0.4.7.tar.gz
|
|
||||||
bbd3e03025168172a76c2a29e6a14c1c37e3476b30774259c3ef5952fb86f470 graalvm-ce-java11-linux-amd64-21.2.0.tar.gz
|
|
|
@ -1,43 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
upgradeSystem
|
|
||||||
|
|
||||||
mkdir -p /usr/share/man/man1
|
|
||||||
apt -qqy install openjdk-11-jre-headless leiningen curl build-essential libz-dev zlib1g-dev
|
|
||||||
|
|
||||||
# shadow-cljs
|
|
||||||
npm install -g --save-dev shadow-cljs
|
|
||||||
|
|
||||||
# download kubeconform & graalvm
|
|
||||||
curl -Lo /tmp/kubeconform-v0.4.7.tar.gz https://github.com/yannh/kubeconform/releases/download/v0.4.7/kubeconform-linux-amd64.tar.gz
|
|
||||||
curl -Lo /tmp/graalvm-ce-java11-linux-amd64-21.2.0.tar.gz https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.2.0/graalvm-ce-java11-linux-amd64-21.2.0.tar.gz
|
|
||||||
|
|
||||||
# checksum
|
|
||||||
cd /tmp
|
|
||||||
sha256sum --check CHECKSUMS
|
|
||||||
|
|
||||||
# install kubeconform
|
|
||||||
tar -xf /tmp/kubeconform-v0.4.7.tar.gz
|
|
||||||
cp kubeconform /usr/local/bin
|
|
||||||
|
|
||||||
# install graalvm
|
|
||||||
tar -xzf graalvm-ce-java11-linux-amd64-21.2.0.tar.gz
|
|
||||||
mv graalvm-ce-java11-21.2.0 /usr/lib/jvm/
|
|
||||||
ln -s /usr/lib/jvm/graalvm-ce-java11-21.2.0 /usr/lib/jvm/graalvm
|
|
||||||
ln -s /usr/lib/jvm/graalvm/bin/gu /usr/local/bin
|
|
||||||
|
|
||||||
update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm/bin/java 2
|
|
||||||
|
|
||||||
gu install native-image
|
|
||||||
ln -s /usr/lib/jvm/graalvm/bin/native-image /usr/local/bin
|
|
||||||
|
|
||||||
#install lein
|
|
||||||
/tmp/lein.sh
|
|
||||||
|
|
||||||
cleanupDocker
|
|
||||||
}
|
|
||||||
|
|
||||||
source /tmp/install_functions.sh
|
|
||||||
main
|
|
|
@ -1,423 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Ensure this file is executable via `chmod a+x lein`, then place it
|
|
||||||
# somewhere on your $PATH, like ~/bin. The rest of Leiningen will be
|
|
||||||
# installed upon first run into the ~/.lein/self-installs directory.
|
|
||||||
|
|
||||||
function msg {
|
|
||||||
echo "$@" 1>&2
|
|
||||||
}
|
|
||||||
|
|
||||||
export LEIN_VERSION="2.9.6"
|
|
||||||
# Must be sha256sum, will be replaced by bin/release
|
|
||||||
export LEIN_CHECKSUM='41c543f73eec4327dc20e60d5d820fc2a9dc772bc671610b9c385d9c4f5970b8'
|
|
||||||
|
|
||||||
case $LEIN_VERSION in
|
|
||||||
*SNAPSHOT) SNAPSHOT="YES" ;;
|
|
||||||
*) SNAPSHOT="NO" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ "$CLASSPATH" != "" ]]; then
|
|
||||||
cat <<-'EOS' 1>&2
|
|
||||||
WARNING: You have $CLASSPATH set, probably by accident.
|
|
||||||
It is strongly recommended to unset this before proceeding.
|
|
||||||
EOS
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then
|
|
||||||
delimiter=";"
|
|
||||||
else
|
|
||||||
delimiter=":"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "cygwin" ]]; then
|
|
||||||
cygwin=true
|
|
||||||
else
|
|
||||||
cygwin=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
function command_not_found {
|
|
||||||
msg "Leiningen couldn't find $1 in your \$PATH ($PATH), which is required."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_native_path {
|
|
||||||
# ensure we have native paths
|
|
||||||
if $cygwin && [[ "$1" == /* ]]; then
|
|
||||||
echo -n "$(cygpath -wp "$1")"
|
|
||||||
elif [[ "$OSTYPE" == "msys" && "$1" == /?/* ]]; then
|
|
||||||
echo -n "$(sh -c "(cd $1 2</dev/null && pwd -W) || echo $1 | sed 's/^\\/\([a-z]\)/\\1:/g'")"
|
|
||||||
else
|
|
||||||
echo -n "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# usage : add_path PATH_VAR [PATH]...
|
|
||||||
function add_path {
|
|
||||||
local path_var="$1"
|
|
||||||
shift
|
|
||||||
while [ -n "$1" ];do
|
|
||||||
# http://bashify.com/?Useful_Techniques:Indirect_Variables:Indirect_Assignment
|
|
||||||
if [[ -z ${!path_var} ]]; then
|
|
||||||
export ${path_var}="$(make_native_path "$1")"
|
|
||||||
else
|
|
||||||
export ${path_var}="${!path_var}${delimiter}$(make_native_path "$1")"
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
function download_failed_message {
|
|
||||||
cat <<-EOS 1>&2
|
|
||||||
Failed to download $1 (exit code $2)
|
|
||||||
It's possible your HTTP client's certificate store does not have the
|
|
||||||
correct certificate authority needed. This is often caused by an
|
|
||||||
out-of-date version of libssl. It's also possible that you're behind a
|
|
||||||
firewall and haven't set HTTP_PROXY and HTTPS_PROXY.
|
|
||||||
EOS
|
|
||||||
}
|
|
||||||
|
|
||||||
function checksum_failed_message {
|
|
||||||
cat <<-EOS 1>&2
|
|
||||||
Failed to properly download $1
|
|
||||||
The checksum was mismatched. and we could not verify the downloaded
|
|
||||||
file. We expected a sha256 of
|
|
||||||
$2 and actually had
|
|
||||||
$3.
|
|
||||||
We used '$SHASUM_CMD' to verify the downloaded file.
|
|
||||||
EOS
|
|
||||||
}
|
|
||||||
|
|
||||||
function self_install {
|
|
||||||
if [ -r "$LEIN_JAR" ]; then
|
|
||||||
cat <<-EOS 1>&2
|
|
||||||
The self-install jar already exists at $LEIN_JAR.
|
|
||||||
If you wish to re-download, delete it and rerun "$0 self-install".
|
|
||||||
EOS
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
msg "Downloading Leiningen to $LEIN_JAR now..."
|
|
||||||
mkdir -p "$(dirname "$LEIN_JAR")"
|
|
||||||
LEIN_URL="https://github.com/technomancy/leiningen/releases/download/$LEIN_VERSION/leiningen-$LEIN_VERSION-standalone.zip"
|
|
||||||
$HTTP_CLIENT "$LEIN_JAR.pending" "$LEIN_URL"
|
|
||||||
local exit_code=$?
|
|
||||||
if [ $exit_code == 0 ]; then
|
|
||||||
printf "$LEIN_CHECKSUM $LEIN_JAR.pending\n" > "$LEIN_JAR.pending.shasum"
|
|
||||||
$SHASUM_CMD -c "$LEIN_JAR.pending.shasum"
|
|
||||||
if [ $? == 0 ]; then
|
|
||||||
mv -f "$LEIN_JAR.pending" "$LEIN_JAR"
|
|
||||||
else
|
|
||||||
got_sum="$($SHASUM_CMD "$LEIN_JAR.pending" | cut -f 1 -d ' ')"
|
|
||||||
checksum_failed_message "$LEIN_URL" "$LEIN_CHECKSUM" "$got_sum"
|
|
||||||
rm "$LEIN_JAR.pending" 2> /dev/null
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
rm "$LEIN_JAR.pending" 2> /dev/null
|
|
||||||
download_failed_message "$LEIN_URL" "$exit_code"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
NOT_FOUND=1
|
|
||||||
ORIGINAL_PWD="$PWD"
|
|
||||||
while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ]
|
|
||||||
do
|
|
||||||
cd ..
|
|
||||||
if [ "$(dirname "$PWD")" = "/" ]; then
|
|
||||||
NOT_FOUND=0
|
|
||||||
cd "$ORIGINAL_PWD"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
export LEIN_HOME="${LEIN_HOME:-"$HOME/.lein"}"
|
|
||||||
|
|
||||||
for f in "/etc/leinrc" "$LEIN_HOME/leinrc" ".leinrc"; do
|
|
||||||
if [ -e "$f" ]; then
|
|
||||||
source "$f"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if $cygwin; then
|
|
||||||
export LEIN_HOME=$(cygpath -w "$LEIN_HOME")
|
|
||||||
fi
|
|
||||||
|
|
||||||
LEIN_JAR="$LEIN_HOME/self-installs/leiningen-$LEIN_VERSION-standalone.jar"
|
|
||||||
|
|
||||||
# normalize $0 on certain BSDs
|
|
||||||
if [ "$(dirname "$0")" = "." ]; then
|
|
||||||
SCRIPT="$(which "$(basename "$0")")"
|
|
||||||
if [ -z "$SCRIPT" ]; then
|
|
||||||
SCRIPT="$0"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
SCRIPT="$0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# resolve symlinks to the script itself portably
|
|
||||||
while [ -h "$SCRIPT" ] ; do
|
|
||||||
ls=$(ls -ld "$SCRIPT")
|
|
||||||
link=$(expr "$ls" : '.*-> \(.*\)$')
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
SCRIPT="$link"
|
|
||||||
else
|
|
||||||
SCRIPT="$(dirname "$SCRIPT"$)/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
BIN_DIR="$(dirname "$SCRIPT")"
|
|
||||||
|
|
||||||
export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-Xverify:none -XX:+TieredCompilation -XX:TieredStopAtLevel=1"}"
|
|
||||||
|
|
||||||
# This needs to be defined before we call HTTP_CLIENT below
|
|
||||||
if [ "$HTTP_CLIENT" = "" ]; then
|
|
||||||
if type -p curl >/dev/null 2>&1; then
|
|
||||||
if [ "$https_proxy" != "" ]; then
|
|
||||||
CURL_PROXY="-x $https_proxy"
|
|
||||||
fi
|
|
||||||
HTTP_CLIENT="curl $CURL_PROXY -f -L -o"
|
|
||||||
else
|
|
||||||
HTTP_CLIENT="wget -O"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This needs to be defined before we call SHASUM_CMD below
|
|
||||||
if [ "$SHASUM_CMD" = "" ]; then
|
|
||||||
if type -p sha256sum >/dev/null 2>&1; then
|
|
||||||
export SHASUM_CMD="sha256sum"
|
|
||||||
elif type -p shasum >/dev/null 2>&1; then
|
|
||||||
export SHASUM_CMD="shasum --algorithm 256"
|
|
||||||
elif type -p sha256 >/dev/null 2>&1; then
|
|
||||||
export SHASUM_CMD="sha256 -q"
|
|
||||||
else
|
|
||||||
command_not_found sha256sum
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# When :eval-in :classloader we need more memory
|
|
||||||
grep -E -q '^\s*:eval-in\s+:classloader\s*$' project.clj 2> /dev/null && \
|
|
||||||
export LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Xms64m -Xmx512m"
|
|
||||||
|
|
||||||
if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then
|
|
||||||
# Running from source checkout
|
|
||||||
LEIN_DIR="$(cd $(dirname "$BIN_DIR");pwd -P)"
|
|
||||||
|
|
||||||
# Need to use lein release to bootstrap the leiningen-core library (for aether)
|
|
||||||
if [ ! -r "$LEIN_DIR/leiningen-core/.lein-bootstrap" ]; then
|
|
||||||
cat <<-'EOS' 1>&2
|
|
||||||
Leiningen is missing its dependencies.
|
|
||||||
Please run "lein bootstrap" in the leiningen-core/ directory
|
|
||||||
with a stable release of Leiningen. See CONTRIBUTING.md for details.
|
|
||||||
EOS
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If project.clj for lein or leiningen-core changes, we must recalculate
|
|
||||||
LAST_PROJECT_CHECKSUM=$(cat "$LEIN_DIR/.lein-project-checksum" 2> /dev/null)
|
|
||||||
PROJECT_CHECKSUM=$(sum "$LEIN_DIR/project.clj" "$LEIN_DIR/leiningen-core/project.clj")
|
|
||||||
if [ "$PROJECT_CHECKSUM" != "$LAST_PROJECT_CHECKSUM" ]; then
|
|
||||||
if [ -r "$LEIN_DIR/.lein-classpath" ]; then
|
|
||||||
rm "$LEIN_DIR/.lein-classpath"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use bin/lein to calculate its own classpath.
|
|
||||||
if [ ! -r "$LEIN_DIR/.lein-classpath" ] && [ "$1" != "classpath" ]; then
|
|
||||||
msg "Recalculating Leiningen's classpath."
|
|
||||||
cd "$LEIN_DIR"
|
|
||||||
|
|
||||||
LEIN_NO_USER_PROFILES=1 "$LEIN_DIR/bin/lein" classpath .lein-classpath
|
|
||||||
sum "$LEIN_DIR/project.clj" "$LEIN_DIR/leiningen-core/project.clj" > \
|
|
||||||
.lein-project-checksum
|
|
||||||
cd -
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$LEIN_DIR/target/classes"
|
|
||||||
export LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Dclojure.compile.path=$LEIN_DIR/target/classes"
|
|
||||||
add_path CLASSPATH "$LEIN_DIR/leiningen-core/src/" "$LEIN_DIR/leiningen-core/resources/" \
|
|
||||||
"$LEIN_DIR/test:$LEIN_DIR/target/classes" "$LEIN_DIR/src" ":$LEIN_DIR/resources"
|
|
||||||
|
|
||||||
if [ -r "$LEIN_DIR/.lein-classpath" ]; then
|
|
||||||
add_path CLASSPATH "$(cat "$LEIN_DIR/.lein-classpath" 2> /dev/null)"
|
|
||||||
else
|
|
||||||
add_path CLASSPATH "$(cat "$LEIN_DIR/leiningen-core/.lein-bootstrap" 2> /dev/null)"
|
|
||||||
fi
|
|
||||||
else # Not running from a checkout
|
|
||||||
add_path CLASSPATH "$LEIN_JAR"
|
|
||||||
|
|
||||||
if [ "$LEIN_USE_BOOTCLASSPATH" != "no" ]; then
|
|
||||||
LEIN_JVM_OPTS="-Xbootclasspath/a:$LEIN_JAR $LEIN_JVM_OPTS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -r "$LEIN_JAR" -a "$1" != "self-install" ]; then
|
|
||||||
self_install
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -x "$JAVA_CMD" ] && ! type -f java >/dev/null
|
|
||||||
then
|
|
||||||
msg "Leiningen couldn't find 'java' executable, which is required."
|
|
||||||
msg "Please either set JAVA_CMD or put java (>=1.6) in your \$PATH ($PATH)."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-${JAVA_CMD:-java}}"
|
|
||||||
|
|
||||||
if [[ -z "${DRIP_INIT+x}" && "$(basename "$LEIN_JAVA_CMD")" == *drip* ]]; then
|
|
||||||
export DRIP_INIT="$(printf -- '-e\n(require (quote leiningen.repl))')"
|
|
||||||
export DRIP_INIT_CLASS="clojure.main"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Support $JAVA_OPTS for backwards-compatibility.
|
|
||||||
export JVM_OPTS="${JVM_OPTS:-"$JAVA_OPTS"}"
|
|
||||||
|
|
||||||
# Handle jline issue with cygwin not propagating OSTYPE through java subprocesses: https://github.com/jline/jline2/issues/62
|
|
||||||
cygterm=false
|
|
||||||
if $cygwin; then
|
|
||||||
case "$TERM" in
|
|
||||||
rxvt* | xterm* | vt*) cygterm=true ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $cygterm; then
|
|
||||||
LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Djline.terminal=jline.UnixTerminal"
|
|
||||||
stty -icanon min 1 -echo > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# TODO: investigate http://skife.org/java/unix/2011/06/20/really_executable_jars.html
|
|
||||||
# If you're packaging this for a package manager (.deb, homebrew, etc)
|
|
||||||
# you need to remove the self-install and upgrade functionality or see lein-pkg.
|
|
||||||
if [ "$1" = "self-install" ]; then
|
|
||||||
if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then
|
|
||||||
cat <<-'EOS' 1>&2
|
|
||||||
Running self-install from a checkout is not supported.
|
|
||||||
See CONTRIBUTING.md for SNAPSHOT-specific build instructions.
|
|
||||||
EOS
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
msg "Manual self-install is deprecated; it will run automatically when necessary."
|
|
||||||
self_install
|
|
||||||
elif [ "$1" = "upgrade" ] || [ "$1" = "downgrade" ]; then
|
|
||||||
if [ "$LEIN_DIR" != "" ]; then
|
|
||||||
msg "The upgrade task is not meant to be run from a checkout."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ $SNAPSHOT = "YES" ]; then
|
|
||||||
cat <<-'EOS' 1>&2
|
|
||||||
The upgrade task is only meant for stable releases.
|
|
||||||
See the "Bootstrapping" section of CONTRIBUTING.md.
|
|
||||||
EOS
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -w "$SCRIPT" ]; then
|
|
||||||
msg "You do not have permission to upgrade the installation in $SCRIPT"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
TARGET_VERSION="${2:-stable}"
|
|
||||||
echo "The script at $SCRIPT will be upgraded to the latest $TARGET_VERSION version."
|
|
||||||
echo -n "Do you want to continue [Y/n]? "
|
|
||||||
read RESP
|
|
||||||
case "$RESP" in
|
|
||||||
y|Y|"")
|
|
||||||
echo
|
|
||||||
msg "Upgrading..."
|
|
||||||
TARGET="/tmp/lein-${$}-upgrade"
|
|
||||||
if $cygwin; then
|
|
||||||
TARGET=$(cygpath -w "$TARGET")
|
|
||||||
fi
|
|
||||||
LEIN_SCRIPT_URL="https://github.com/technomancy/leiningen/raw/$TARGET_VERSION/bin/lein"
|
|
||||||
$HTTP_CLIENT "$TARGET" "$LEIN_SCRIPT_URL"
|
|
||||||
if [ $? == 0 ]; then
|
|
||||||
cmp -s "$TARGET" "$SCRIPT"
|
|
||||||
if [ $? == 0 ]; then
|
|
||||||
msg "Leiningen is already up-to-date."
|
|
||||||
fi
|
|
||||||
mv "$TARGET" "$SCRIPT" && chmod +x "$SCRIPT"
|
|
||||||
unset CLASSPATH
|
|
||||||
exec "$SCRIPT" version
|
|
||||||
else
|
|
||||||
download_failed_message "$LEIN_SCRIPT_URL"
|
|
||||||
fi;;
|
|
||||||
*)
|
|
||||||
msg "Aborted."
|
|
||||||
exit 1;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if $cygwin; then
|
|
||||||
# When running on Cygwin, use Windows-style paths for java
|
|
||||||
ORIGINAL_PWD=$(cygpath -w "$ORIGINAL_PWD")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# apply context specific CLASSPATH entries
|
|
||||||
if [ -f .lein-classpath ]; then
|
|
||||||
add_path CLASSPATH "$(cat .lein-classpath)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$DEBUG" ]; then
|
|
||||||
msg "Leiningen's classpath: $CLASSPATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -r .lein-fast-trampoline ]; then
|
|
||||||
export LEIN_FAST_TRAMPOLINE='y'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$LEIN_FAST_TRAMPOLINE" != "" ] && [ -r project.clj ]; then
|
|
||||||
INPUTS="$* $(cat project.clj) $LEIN_VERSION $(test -f "$LEIN_HOME/profiles.clj" && cat "$LEIN_HOME/profiles.clj") $(test -f profiles.clj && cat profiles.clj)"
|
|
||||||
|
|
||||||
INPUT_CHECKSUM=$(echo "$INPUTS" | $SHASUM_CMD | cut -f 1 -d " ")
|
|
||||||
# Just don't change :target-path in project.clj, mkay?
|
|
||||||
TRAMPOLINE_FILE="target/trampolines/$INPUT_CHECKSUM"
|
|
||||||
else
|
|
||||||
if hash mktemp 2>/dev/null; then
|
|
||||||
# Check if mktemp is available before using it
|
|
||||||
TRAMPOLINE_FILE="$(mktemp /tmp/lein-trampoline-XXXXXXXXXXXXX)"
|
|
||||||
else
|
|
||||||
TRAMPOLINE_FILE="/tmp/lein-trampoline-$$"
|
|
||||||
fi
|
|
||||||
trap 'rm -f $TRAMPOLINE_FILE' EXIT
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $cygwin; then
|
|
||||||
TRAMPOLINE_FILE=$(cygpath -w "$TRAMPOLINE_FILE")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$INPUT_CHECKSUM" != "" ] && [ -r "$TRAMPOLINE_FILE" ]; then
|
|
||||||
if [ -n "$DEBUG" ]; then
|
|
||||||
msg "Fast trampoline with $TRAMPOLINE_FILE."
|
|
||||||
fi
|
|
||||||
exec sh -c "exec $(cat "$TRAMPOLINE_FILE")"
|
|
||||||
else
|
|
||||||
export TRAMPOLINE_FILE
|
|
||||||
"$LEIN_JAVA_CMD" \
|
|
||||||
-Dfile.encoding=UTF-8 \
|
|
||||||
-Dmaven.wagon.http.ssl.easy=false \
|
|
||||||
-Dmaven.wagon.rto=10000 \
|
|
||||||
$LEIN_JVM_OPTS \
|
|
||||||
-Dleiningen.input-checksum="$INPUT_CHECKSUM" \
|
|
||||||
-Dleiningen.original.pwd="$ORIGINAL_PWD" \
|
|
||||||
-Dleiningen.script="$SCRIPT" \
|
|
||||||
-classpath "$CLASSPATH" \
|
|
||||||
clojure.main -m leiningen.core.main "$@"
|
|
||||||
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
if $cygterm ; then
|
|
||||||
stty icanon echo > /dev/null 2>&1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -r "$TRAMPOLINE_FILE" ] && [ "$LEIN_TRAMPOLINE_WARMUP" = "" ]; then
|
|
||||||
TRAMPOLINE="$(cat "$TRAMPOLINE_FILE")"
|
|
||||||
if [ "$INPUT_CHECKSUM" = "" ]; then # not using fast trampoline
|
|
||||||
rm "$TRAMPOLINE_FILE"
|
|
||||||
fi
|
|
||||||
if [ "$TRAMPOLINE" = "" ]; then
|
|
||||||
exit $EXIT_CODE
|
|
||||||
else
|
|
||||||
exec sh -c "exec $TRAMPOLINE"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit $EXIT_CODE
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
|
@ -1,11 +0,0 @@
|
||||||
FROM clojure
|
|
||||||
|
|
||||||
RUN apt update
|
|
||||||
RUN apt -yqq --no-install-recommends --yes install curl default-jre-headless
|
|
||||||
|
|
||||||
RUN curl -L -o /tmp/serverspec.jar \
|
|
||||||
https://github.com/DomainDrivenArchitecture/dda-serverspec-crate/releases/download/2.0.0/dda-serverspec-standalone.jar
|
|
||||||
|
|
||||||
COPY serverspec.edn /tmp/serverspec.edn
|
|
||||||
|
|
||||||
RUN java -jar /tmp/serverspec.jar /tmp/serverspec.edn -v
|
|
|
@ -1 +0,0 @@
|
||||||
{}
|
|
57
infrastructure/ddadevops/build.py
Normal file
57
infrastructure/ddadevops/build.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
|
||||||
|
name = "ddadevops"
|
||||||
|
MODULE = "ddadevops"
|
||||||
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": ["IMAGE"],
|
||||||
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_ONLY",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build_depends_on("ddadevops>=4.9.0")
|
||||||
|
|
||||||
|
build = DevopsImageBuild(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def image(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.image()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def drun(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.drun()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def test(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.test()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def publish(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.dockerhub_login()
|
||||||
|
build.dockerhub_publish()
|
5
infrastructure/ddadevops/image/Dockerfile
Normal file
5
infrastructure/ddadevops/image/Dockerfile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
FROM python:3.10-alpine
|
||||||
|
|
||||||
|
ADD resources /tmp
|
||||||
|
|
||||||
|
RUN /tmp/install.sh
|
19
infrastructure/ddadevops/image/resources/install.sh
Executable file
19
infrastructure/ddadevops/image/resources/install.sh
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
apk add --no-cache python3 py3-pip openssl-dev bash git curl
|
||||||
|
python3 -m pip install -U pip
|
||||||
|
pip3 install pybuilder ddadevops deprecation dda-python-terraform boto3 pyyaml inflection
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_alpine.sh
|
||||||
|
main
|
|
@ -1,6 +0,0 @@
|
||||||
FROM docker:latest
|
|
||||||
|
|
||||||
RUN set -eux;
|
|
||||||
RUN apk add --no-cache build-base rust python3 python3-dev py3-pip py3-setuptools py3-wheel libffi-dev openssl-dev cargo bash git;
|
|
||||||
RUN python3 -m pip install -U pip;
|
|
||||||
RUN pip3 install pybuilder ddadevops deprecation dda-python-terraform boto3 pyyaml;
|
|
|
@ -1,11 +0,0 @@
|
||||||
FROM devops-build
|
|
||||||
|
|
||||||
RUN apk update
|
|
||||||
RUN apk add curl openjdk8
|
|
||||||
|
|
||||||
RUN curl -L -o /tmp/serverspec.jar \
|
|
||||||
https://github.com/DomainDrivenArchitecture/dda-serverspec-crate/releases/download/2.0.0/dda-serverspec-standalone.jar
|
|
||||||
|
|
||||||
COPY serverspec.edn /tmp/serverspec.edn
|
|
||||||
|
|
||||||
RUN java -jar /tmp/serverspec.jar /tmp/serverspec.edn -v
|
|
|
@ -1 +0,0 @@
|
||||||
{}
|
|
57
infrastructure/dind/build.py
Normal file
57
infrastructure/dind/build.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
|
||||||
|
name = "ddadevops"
|
||||||
|
MODULE = "dind"
|
||||||
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": ["IMAGE"],
|
||||||
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_AND_MODULE",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build_depends_on("ddadevops>=4.7.0")
|
||||||
|
|
||||||
|
build = DevopsImageBuild(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def image(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.image()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def drun(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.drun()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def test(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.test()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def publish(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.dockerhub_login()
|
||||||
|
build.dockerhub_publish()
|
5
infrastructure/dind/image/Dockerfile
Normal file
5
infrastructure/dind/image/Dockerfile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
FROM docker:latest
|
||||||
|
|
||||||
|
WORKDIR /tmp
|
||||||
|
ADD resources ./
|
||||||
|
RUN ./install.sh
|
17
infrastructure/dind/image/resources/install.sh
Executable file
17
infrastructure/dind/image/resources/install.sh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
apk add --no-cache python3 py3-pip openssl-dev bash git
|
||||||
|
pip3 install --break-system-packages pybuilder ddadevops deprecation dda-python-terraform boto3 pyyaml inflection
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_alpine.sh
|
||||||
|
main
|
57
infrastructure/kotlin/build.py
Normal file
57
infrastructure/kotlin/build.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
|
from pybuilder.core import task, init
|
||||||
|
from ddadevops import *
|
||||||
|
|
||||||
|
name = "ddadevops"
|
||||||
|
MODULE = "kotlin"
|
||||||
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
|
|
||||||
|
@init
|
||||||
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
|
input = {
|
||||||
|
"name": name,
|
||||||
|
"module": MODULE,
|
||||||
|
"stage": "notused",
|
||||||
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
|
"build_types": ["IMAGE"],
|
||||||
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_AND_MODULE",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build_depends_on("ddadevops>=4.0.0")
|
||||||
|
|
||||||
|
build = DevopsImageBuild(project, input)
|
||||||
|
build.initialize_build_dir()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def image(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.image()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def drun(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.drun()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def test(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.test()
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def publish(project):
|
||||||
|
build = get_devops_build(project)
|
||||||
|
build.dockerhub_login()
|
||||||
|
build.dockerhub_publish()
|
4
infrastructure/kotlin/image/Dockerfile
Normal file
4
infrastructure/kotlin/image/Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
FROM debian:stable-slim
|
||||||
|
|
||||||
|
ADD resources /tmp
|
||||||
|
RUN /tmp/install.sh
|
17
infrastructure/kotlin/image/resources/install.sh
Executable file
17
infrastructure/kotlin/image/resources/install.sh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
apt-get -qqy install curl git kotlin gradle iputils-ping ssh python3 python3-pip
|
||||||
|
|
||||||
|
pip3 install --break-system-packages pybuilder 'ddadevops>=4.7.0' deprecation dda-python-terraform boto3 pyyaml inflection
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_debian.sh
|
||||||
|
DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes main
|
|
@ -1,14 +1,19 @@
|
||||||
from os import environ
|
from os import environ
|
||||||
|
from datetime import datetime
|
||||||
from pybuilder.core import task, init
|
from pybuilder.core import task, init
|
||||||
from ddadevops import *
|
from ddadevops import *
|
||||||
|
|
||||||
name = "devops-build"
|
name = "ddadevops"
|
||||||
MODULE = "image"
|
MODULE = "python"
|
||||||
PROJECT_ROOT_PATH = "../.."
|
PROJECT_ROOT_PATH = "../.."
|
||||||
|
version = "4.13.2-dev"
|
||||||
|
|
||||||
|
|
||||||
@init
|
@init
|
||||||
def initialize(project):
|
def initialize(project):
|
||||||
|
image_tag = version
|
||||||
|
if "dev" in image_tag:
|
||||||
|
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -17,6 +22,8 @@ def initialize(project):
|
||||||
"project_root_path": PROJECT_ROOT_PATH,
|
"project_root_path": PROJECT_ROOT_PATH,
|
||||||
"build_types": ["IMAGE"],
|
"build_types": ["IMAGE"],
|
||||||
"mixin_types": [],
|
"mixin_types": [],
|
||||||
|
"image_naming": "NAME_AND_MODULE",
|
||||||
|
"image_tag": f"{image_tag}",
|
||||||
}
|
}
|
||||||
|
|
||||||
project.build_depends_on("ddadevops>=4.0.0")
|
project.build_depends_on("ddadevops>=4.0.0")
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:lts-buster-slim
|
FROM python:3.10-alpine
|
||||||
|
|
||||||
ADD resources /tmp
|
ADD resources /tmp
|
||||||
RUN /tmp/install.sh
|
RUN /tmp/install.sh
|
20
infrastructure/python/image/resources/install.sh
Executable file
20
infrastructure/python/image/resources/install.sh
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
{
|
||||||
|
upgradeSystem
|
||||||
|
|
||||||
|
apk add --no-cache build-base rust python3 python3-dev py3-pip py3-setuptools py3-wheel libffi-dev openssl-dev cargo bash git curl
|
||||||
|
python3 -m pip install -U pip
|
||||||
|
pip3 install pybuilder ddadevops deprecation dda-python-terraform boto3 pyyaml inflection \
|
||||||
|
coverage flake8 flake8-polyfill mypy mypy-extensions pycodestyle pyflakes pylint pytest pytest-cov pytest-datafiles types-setuptools types-PyYAML
|
||||||
|
|
||||||
|
cleanupDocker
|
||||||
|
|
||||||
|
} > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
source /tmp/install_functions_alpine.sh
|
||||||
|
main
|
|
@ -4,7 +4,9 @@ from ..infrastructure import FileApi, ResourceApi, ImageApi
|
||||||
|
|
||||||
|
|
||||||
class ImageBuildService:
|
class ImageBuildService:
|
||||||
def __init__(self, file_api: FileApi, resource_api: ResourceApi, image_api: ImageApi):
|
def __init__(
|
||||||
|
self, file_api: FileApi, resource_api: ResourceApi, image_api: ImageApi
|
||||||
|
):
|
||||||
self.file_api = file_api
|
self.file_api = file_api
|
||||||
self.resource_api = resource_api
|
self.resource_api = resource_api
|
||||||
self.image_api = image_api
|
self.image_api = image_api
|
||||||
|
@ -18,7 +20,9 @@ class ImageBuildService:
|
||||||
)
|
)
|
||||||
|
|
||||||
def __copy_build_resource_file_from_package__(self, resource_name, devops: Devops):
|
def __copy_build_resource_file_from_package__(self, resource_name, devops: Devops):
|
||||||
data = self.resource_api.read_resource(f"src/main/resources/docker/{resource_name}")
|
data = self.resource_api.read_resource(
|
||||||
|
f"src/main/resources/docker/{resource_name}"
|
||||||
|
)
|
||||||
self.file_api.write_data_to_file(
|
self.file_api.write_data_to_file(
|
||||||
Path(f"{devops.build_path()}/{resource_name}"), data
|
Path(f"{devops.build_path()}/{resource_name}"), data
|
||||||
)
|
)
|
||||||
|
@ -27,12 +31,16 @@ class ImageBuildService:
|
||||||
self.__copy_build_resource_file_from_package__(
|
self.__copy_build_resource_file_from_package__(
|
||||||
"image/resources/install_functions.sh", devops
|
"image/resources/install_functions.sh", devops
|
||||||
)
|
)
|
||||||
|
self.__copy_build_resource_file_from_package__(
|
||||||
|
"image/resources/install_functions_debian.sh", devops
|
||||||
|
)
|
||||||
|
self.__copy_build_resource_file_from_package__(
|
||||||
|
"image/resources/install_functions_alpine.sh", devops
|
||||||
|
)
|
||||||
|
|
||||||
def __copy_build_resources_from_dir__(self, devops: Devops):
|
def __copy_build_resources_from_dir__(self, devops: Devops):
|
||||||
image = devops.specialized_builds[BuildType.IMAGE]
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
self.file_api.cp_force(
|
self.file_api.cp_force(image.build_commons_path(), devops.build_path())
|
||||||
image.build_commons_path(), devops.build_path()
|
|
||||||
)
|
|
||||||
|
|
||||||
def initialize_build_dir(self, devops: Devops):
|
def initialize_build_dir(self, devops: Devops):
|
||||||
image = devops.specialized_builds[BuildType.IMAGE]
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
@ -43,13 +51,18 @@ class ImageBuildService:
|
||||||
else:
|
else:
|
||||||
self.__copy_build_resources_from_dir__(devops)
|
self.__copy_build_resources_from_dir__(devops)
|
||||||
self.file_api.cp_recursive("image", build_path)
|
self.file_api.cp_recursive("image", build_path)
|
||||||
|
try:
|
||||||
self.file_api.cp_recursive("test", build_path)
|
self.file_api.cp_recursive("test", build_path)
|
||||||
|
except:
|
||||||
|
print("Folder 'test' not found")
|
||||||
|
|
||||||
def image(self, devops: Devops):
|
def image(self, devops: Devops):
|
||||||
self.image_api.image(devops.name, devops.build_path())
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
self.image_api.image(image.image_name(), devops.build_path())
|
||||||
|
|
||||||
def drun(self, devops: Devops):
|
def drun(self, devops: Devops):
|
||||||
self.image_api.drun(devops.name)
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
self.image_api.drun(image.image_name())
|
||||||
|
|
||||||
def dockerhub_login(self, devops: Devops):
|
def dockerhub_login(self, devops: Devops):
|
||||||
image = devops.specialized_builds[BuildType.IMAGE]
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
@ -59,9 +72,14 @@ class ImageBuildService:
|
||||||
|
|
||||||
def dockerhub_publish(self, devops: Devops):
|
def dockerhub_publish(self, devops: Devops):
|
||||||
image = devops.specialized_builds[BuildType.IMAGE]
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
if image.image_tag is not None:
|
||||||
self.image_api.dockerhub_publish(
|
self.image_api.dockerhub_publish(
|
||||||
devops.name, image.image_dockerhub_user, image.image_tag
|
image.image_name(), image.image_dockerhub_user, image.image_tag
|
||||||
|
)
|
||||||
|
self.image_api.dockerhub_publish(
|
||||||
|
image.image_name(), image.image_dockerhub_user, 'latest'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test(self, devops: Devops):
|
def test(self, devops: Devops):
|
||||||
self.image_api.test(devops.name, devops.build_path())
|
image = devops.specialized_builds[BuildType.IMAGE]
|
||||||
|
self.image_api.test(image.image_name(), devops.build_path())
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
|
import json
|
||||||
from typing import List
|
from typing import List
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ..infrastructure import GitApi, BuildFileRepository
|
from ..infrastructure import GitApi, ArtifactDeploymentApi, BuildFileRepository
|
||||||
from ..domain import Version, Release, ReleaseType
|
from ..domain import Version, Release, ReleaseType, Artifact
|
||||||
|
|
||||||
|
|
||||||
class ReleaseService:
|
class ReleaseService:
|
||||||
def __init__(self, git_api: GitApi, build_file_repository: BuildFileRepository):
|
def __init__(
|
||||||
|
self,
|
||||||
|
git_api: GitApi,
|
||||||
|
artifact_deployment_api: ArtifactDeploymentApi,
|
||||||
|
build_file_repository: BuildFileRepository,
|
||||||
|
):
|
||||||
self.git_api = git_api
|
self.git_api = git_api
|
||||||
|
self.artifact_deployment_api = artifact_deployment_api
|
||||||
self.build_file_repository = build_file_repository
|
self.build_file_repository = build_file_repository
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prod(cls, base_dir: str):
|
def prod(cls, base_dir: str):
|
||||||
return cls(
|
return cls(
|
||||||
GitApi(),
|
GitApi(),
|
||||||
|
ArtifactDeploymentApi(),
|
||||||
BuildFileRepository(base_dir),
|
BuildFileRepository(base_dir),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,7 +53,8 @@ class ReleaseService:
|
||||||
bump_version = release_version.create_bump()
|
bump_version = release_version.create_bump()
|
||||||
release_message = f"release: {release_version.to_string()}"
|
release_message = f"release: {release_version.to_string()}"
|
||||||
bump_message = f"bump version to: {bump_version.to_string()}"
|
bump_message = f"bump version to: {bump_version.to_string()}"
|
||||||
self.git_api.tag_annotated(release_version.to_string(), release_message, 0)
|
release_tag = f"{release.release_tag_prefix}{release_version.to_string()}"
|
||||||
|
self.git_api.tag_annotated(release_tag, release_message, 0)
|
||||||
self.__set_version_and_commit__(
|
self.__set_version_and_commit__(
|
||||||
bump_version,
|
bump_version,
|
||||||
release.build_files(),
|
release.build_files(),
|
||||||
|
@ -53,6 +62,41 @@ class ReleaseService:
|
||||||
)
|
)
|
||||||
self.git_api.push_follow_tags()
|
self.git_api.push_follow_tags()
|
||||||
|
|
||||||
|
def publish_artifacts(self, release: Release):
|
||||||
|
token = str(release.release_artifact_token)
|
||||||
|
release_id = self.__parse_forgejo_release_id__(
|
||||||
|
self.artifact_deployment_api.create_forgejo_release(
|
||||||
|
release.forgejo_release_api_endpoint(),
|
||||||
|
release.version.to_string(),
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
artifacts_sums = []
|
||||||
|
for artifact in release.release_artifacts:
|
||||||
|
sha256 = self.artifact_deployment_api.calculate_sha256(artifact.path())
|
||||||
|
sha512 = self.artifact_deployment_api.calculate_sha512(artifact.path())
|
||||||
|
artifacts_sums += [Artifact(sha256), Artifact(sha512)]
|
||||||
|
|
||||||
|
artifacts = release.release_artifacts + artifacts_sums
|
||||||
|
print(artifacts)
|
||||||
|
for artifact in artifacts:
|
||||||
|
print(str)
|
||||||
|
self.artifact_deployment_api.add_asset_to_release(
|
||||||
|
release.forgejo_release_asset_api_endpoint(release_id),
|
||||||
|
artifact.path(),
|
||||||
|
artifact.type(),
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __parse_forgejo_release_id__(self, release_response: str) -> int:
|
||||||
|
parsed = json.loads(release_response)
|
||||||
|
try:
|
||||||
|
result = parsed["id"]
|
||||||
|
except:
|
||||||
|
raise RuntimeError(str(parsed))
|
||||||
|
return result
|
||||||
|
|
||||||
def __set_version_and_commit__(
|
def __set_version_and_commit__(
|
||||||
self, version: Version, build_file_ids: List[str], message: str
|
self, version: Version, build_file_ids: List[str], message: str
|
||||||
):
|
):
|
||||||
|
|
|
@ -17,6 +17,7 @@ from .provider_hetzner import Hetzner
|
||||||
from .provider_aws import Aws
|
from .provider_aws import Aws
|
||||||
from .provs_k3s import K3s
|
from .provs_k3s import K3s
|
||||||
from .release import Release
|
from .release import Release
|
||||||
|
from .artifact import Artifact
|
||||||
from .credentials import Credentials, CredentialMapping, GopassType
|
from .credentials import Credentials, CredentialMapping, GopassType
|
||||||
from .version import Version
|
from .version import Version
|
||||||
from .build_file import BuildFileType, BuildFile
|
from .build_file import BuildFileType, BuildFile
|
||||||
|
|
46
src/main/python/ddadevops/domain/artifact.py
Normal file
46
src/main/python/ddadevops/domain/artifact.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
from .common import (
|
||||||
|
Validateable,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ArtifactType(Enum):
|
||||||
|
TEXT = 0
|
||||||
|
JAR = 1
|
||||||
|
|
||||||
|
|
||||||
|
class Artifact(Validateable):
|
||||||
|
def __init__(self, path: str):
|
||||||
|
self.path_str = path
|
||||||
|
|
||||||
|
def path(self) -> Path:
|
||||||
|
return Path(self.path_str)
|
||||||
|
|
||||||
|
def type(self) -> str:
|
||||||
|
suffix = self.path().suffix
|
||||||
|
match suffix:
|
||||||
|
case ".jar":
|
||||||
|
return "application/x-java-archive"
|
||||||
|
case ".js":
|
||||||
|
return "application/x-javascript"
|
||||||
|
case _:
|
||||||
|
return "text/plain"
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
result = []
|
||||||
|
result += self.__validate_is_not_empty__("path_str")
|
||||||
|
try:
|
||||||
|
Path(self.path_str)
|
||||||
|
except Exception as e:
|
||||||
|
result += [f"path was not a valid: {e}"]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.path())
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return other and self.__str__() == other.__str__()
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return self.__str__().__hash__()
|
|
@ -11,6 +11,7 @@ class BuildFileType(Enum):
|
||||||
JS = ".json"
|
JS = ".json"
|
||||||
JAVA_GRADLE = ".gradle"
|
JAVA_GRADLE = ".gradle"
|
||||||
JAVA_CLOJURE = ".clj"
|
JAVA_CLOJURE = ".clj"
|
||||||
|
JAVA_CLOJURE_EDN = ".edn"
|
||||||
PYTHON = ".py"
|
PYTHON = ".py"
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,42 +42,42 @@ class BuildFile(Validateable):
|
||||||
result = BuildFileType.JAVA_CLOJURE
|
result = BuildFileType.JAVA_CLOJURE
|
||||||
case ".py":
|
case ".py":
|
||||||
result = BuildFileType.PYTHON
|
result = BuildFileType.PYTHON
|
||||||
|
case ".edn":
|
||||||
|
result = BuildFileType.JAVA_CLOJURE_EDN
|
||||||
case _:
|
case _:
|
||||||
result = None
|
result = None
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def __get_file_type_regex_str(self, file_type: BuildFileType):
|
||||||
|
match file_type:
|
||||||
|
case BuildFileType.JAVA_GRADLE:
|
||||||
|
return r"(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
|
||||||
|
case BuildFileType.PYTHON:
|
||||||
|
return r"(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT|-dev\d*)?)\""
|
||||||
|
case BuildFileType.JAVA_CLOJURE:
|
||||||
|
return r"(?P<pre_version>\(defproject\s(\S)*\s)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
|
||||||
|
case BuildFileType.JAVA_CLOJURE_EDN:
|
||||||
|
return r"(?P<pre_version>\:version\s+)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
|
||||||
|
case _:
|
||||||
|
return ""
|
||||||
|
|
||||||
def get_version(self) -> Version:
|
def get_version(self) -> Version:
|
||||||
try:
|
try:
|
||||||
match self.build_file_type():
|
build_file_type = self.build_file_type()
|
||||||
|
match build_file_type:
|
||||||
case BuildFileType.JS:
|
case BuildFileType.JS:
|
||||||
version_str = json.loads(self.content)["version"]
|
version_str = json.loads(self.content)["version"]
|
||||||
case BuildFileType.JAVA_GRADLE:
|
case (
|
||||||
# TODO: '\nversion = ' will not parse all ?!
|
BuildFileType.JAVA_GRADLE
|
||||||
version_line = re.search("\nversion = .*", self.content)
|
| BuildFileType.PYTHON
|
||||||
version_line_group = version_line.group()
|
| BuildFileType.JAVA_CLOJURE
|
||||||
version_string = re.search(
|
| BuildFileType.JAVA_CLOJURE_EDN
|
||||||
"[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?", version_line_group
|
):
|
||||||
)
|
version_str = re.search(
|
||||||
version_str = version_string.group()
|
self.__get_file_type_regex_str(build_file_type), self.content
|
||||||
case BuildFileType.PYTHON:
|
).group("version")
|
||||||
# TODO: '\nversion = ' will not parse all ?!
|
|
||||||
version_line = re.search("\nversion = .*\n", self.content)
|
|
||||||
version_line_group = version_line.group()
|
|
||||||
version_string = re.search(
|
|
||||||
"[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?(-dev)?[0-9]*",
|
|
||||||
version_line_group,
|
|
||||||
)
|
|
||||||
version_str = version_string.group()
|
|
||||||
case BuildFileType.JAVA_CLOJURE:
|
|
||||||
# TODO: unsure about the trailing '\n' !
|
|
||||||
version_line = re.search("\\(defproject .*\n", self.content)
|
|
||||||
version_line_group = version_line.group()
|
|
||||||
version_string = re.search(
|
|
||||||
"[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?", version_line_group
|
|
||||||
)
|
|
||||||
version_str = version_string.group()
|
|
||||||
except:
|
except:
|
||||||
raise Exception(f"Version not found in file {self.file_path}")
|
raise RuntimeError(f"Version not found in file {self.file_path}")
|
||||||
|
|
||||||
result = Version.from_str(version_str, self.get_default_suffix())
|
result = Version.from_str(version_str, self.get_default_suffix())
|
||||||
result.throw_if_invalid()
|
result.throw_if_invalid()
|
||||||
|
@ -84,38 +85,32 @@ class BuildFile(Validateable):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def set_version(self, new_version: Version):
|
def set_version(self, new_version: Version):
|
||||||
# TODO: How can we create regex-pattern constants to use them at both places?
|
|
||||||
|
if new_version.is_snapshot():
|
||||||
|
new_version.snapshot_suffix = self.get_default_suffix()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
match self.build_file_type():
|
build_file_type = self.build_file_type()
|
||||||
|
match build_file_type:
|
||||||
case BuildFileType.JS:
|
case BuildFileType.JS:
|
||||||
json_data = json.loads(self.content)
|
json_data = json.loads(self.content)
|
||||||
json_data["version"] = new_version.to_string()
|
json_data["version"] = new_version.to_string()
|
||||||
self.content = json.dumps(json_data, indent=4)
|
self.content = json.dumps(json_data, indent=4)
|
||||||
case BuildFileType.JAVA_GRADLE:
|
case (
|
||||||
|
BuildFileType.JAVA_GRADLE
|
||||||
|
| BuildFileType.PYTHON
|
||||||
|
| BuildFileType.JAVA_CLOJURE
|
||||||
|
| BuildFileType.JAVA_CLOJURE_EDN
|
||||||
|
):
|
||||||
substitute = re.sub(
|
substitute = re.sub(
|
||||||
'\nversion = "[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?"',
|
self.__get_file_type_regex_str(build_file_type),
|
||||||
f'\nversion = "{new_version.to_string()}"',
|
rf'\g<pre_version>"{new_version.to_string()}"',
|
||||||
self.content,
|
|
||||||
)
|
|
||||||
self.content = substitute
|
|
||||||
case BuildFileType.PYTHON:
|
|
||||||
substitute = re.sub(
|
|
||||||
'\nversion = "[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?(-dev)?[0-9]*"',
|
|
||||||
f'\nversion = "{new_version.to_string()}"',
|
|
||||||
self.content,
|
|
||||||
)
|
|
||||||
self.content = substitute
|
|
||||||
case BuildFileType.JAVA_CLOJURE:
|
|
||||||
# TODO: we should stick here on defproject instead of first line!
|
|
||||||
substitute = re.sub(
|
|
||||||
'"[0-9]*\\.[0-9]*\\.[0-9]*(-SNAPSHOT)?"',
|
|
||||||
f'"{new_version.to_string()}"',
|
|
||||||
self.content,
|
self.content,
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
self.content = substitute
|
self.content = substitute
|
||||||
except:
|
except:
|
||||||
raise Exception(f"Version not found in file {self.file_path}")
|
raise RuntimeError(f"Version not found in file {self.file_path}")
|
||||||
|
|
||||||
def get_default_suffix(self) -> str:
|
def get_default_suffix(self) -> str:
|
||||||
result = "SNAPSHOT"
|
result = "SNAPSHOT"
|
||||||
|
|
|
@ -78,6 +78,12 @@ class DnsRecord(Validateable):
|
||||||
result.append("ipv4 & ipv6 may not both be empty.")
|
result.append("ipv4 & ipv6 may not both be empty.")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def ip(self) -> str:
|
||||||
|
if (self.ipv4):
|
||||||
|
return self.ipv4
|
||||||
|
else:
|
||||||
|
return self.ipv6
|
||||||
|
|
||||||
|
|
||||||
class Devops(Validateable):
|
class Devops(Validateable):
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from enum import Enum
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
from .common import (
|
from .common import (
|
||||||
filter_none,
|
filter_none,
|
||||||
|
@ -5,15 +6,23 @@ from .common import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NamingType(Enum):
|
||||||
|
NAME_ONLY = 1
|
||||||
|
NAME_AND_MODULE = 2
|
||||||
|
|
||||||
|
|
||||||
class Image(Validateable):
|
class Image(Validateable):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
inp: dict,
|
inp: dict,
|
||||||
):
|
):
|
||||||
|
self.module = inp.get("module")
|
||||||
|
self.name = inp.get("name")
|
||||||
self.image_dockerhub_user = inp.get("image_dockerhub_user")
|
self.image_dockerhub_user = inp.get("image_dockerhub_user")
|
||||||
self.image_dockerhub_password = inp.get("image_dockerhub_password")
|
self.image_dockerhub_password = inp.get("image_dockerhub_password")
|
||||||
self.image_tag = inp.get("image_tag")
|
self.image_tag = inp.get("image_tag")
|
||||||
self.image_build_commons_path = inp.get("image_build_commons_path")
|
self.image_build_commons_path = inp.get("image_build_commons_path")
|
||||||
|
self.image_naming = NamingType[inp.get("image_naming", "NAME_ONLY")]
|
||||||
self.image_use_package_common_files = inp.get(
|
self.image_use_package_common_files = inp.get(
|
||||||
"image_use_package_common_files", True
|
"image_use_package_common_files", True
|
||||||
)
|
)
|
||||||
|
@ -23,8 +32,10 @@ class Image(Validateable):
|
||||||
|
|
||||||
def validate(self) -> List[str]:
|
def validate(self) -> List[str]:
|
||||||
result = []
|
result = []
|
||||||
|
result += self.__validate_is_not_empty__("name")
|
||||||
result += self.__validate_is_not_empty__("image_dockerhub_user")
|
result += self.__validate_is_not_empty__("image_dockerhub_user")
|
||||||
result += self.__validate_is_not_empty__("image_dockerhub_password")
|
result += self.__validate_is_not_empty__("image_dockerhub_password")
|
||||||
|
result += self.__validate_is_not_empty__("image_naming")
|
||||||
if not self.image_use_package_common_files:
|
if not self.image_use_package_common_files:
|
||||||
result += self.__validate_is_not_empty__("image_build_commons_path")
|
result += self.__validate_is_not_empty__("image_build_commons_path")
|
||||||
result += self.__validate_is_not_empty__("image_build_commons_dir_name")
|
result += self.__validate_is_not_empty__("image_build_commons_dir_name")
|
||||||
|
@ -37,6 +48,16 @@ class Image(Validateable):
|
||||||
]
|
]
|
||||||
return "/".join(filter_none(commons_path)) + "/"
|
return "/".join(filter_none(commons_path)) + "/"
|
||||||
|
|
||||||
|
def image_name(self) -> str:
|
||||||
|
result: List[str] = [self.name] # type: ignore
|
||||||
|
if (
|
||||||
|
self.image_naming == NamingType.NAME_AND_MODULE
|
||||||
|
and self.module
|
||||||
|
and self.module != ""
|
||||||
|
):
|
||||||
|
result.append(self.module)
|
||||||
|
return "-".join(result)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_mapping_default(cls) -> List[Dict[str, str]]:
|
def get_mapping_default(cls) -> List[Dict[str, str]]:
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -8,7 +8,7 @@ from .provider_digitalocean import Digitalocean
|
||||||
from .provider_hetzner import Hetzner
|
from .provider_hetzner import Hetzner
|
||||||
from .c4k import C4k
|
from .c4k import C4k
|
||||||
from .image import Image
|
from .image import Image
|
||||||
from .release import ReleaseType
|
from .release import ReleaseType, Release
|
||||||
from ..infrastructure import BuildFileRepository, CredentialsApi, EnvironmentApi, GitApi
|
from ..infrastructure import BuildFileRepository, CredentialsApi, EnvironmentApi, GitApi
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ class InitService:
|
||||||
Path(primary_build_file_id)
|
Path(primary_build_file_id)
|
||||||
)
|
)
|
||||||
version = primary_build_file.get_version()
|
version = primary_build_file.get_version()
|
||||||
|
default_mappings += Release.get_mapping_default()
|
||||||
|
|
||||||
credentials = Credentials(inp, default_mappings)
|
credentials = Credentials(inp, default_mappings)
|
||||||
authorization = self.authorization(credentials)
|
authorization = self.authorization(credentials)
|
||||||
|
@ -111,9 +112,8 @@ class InitService:
|
||||||
result = {}
|
result = {}
|
||||||
for name in credentials.mappings.keys():
|
for name in credentials.mappings.keys():
|
||||||
mapping = credentials.mappings[name]
|
mapping = credentials.mappings[name]
|
||||||
env_value = self.environment_api.get(mapping.name_for_environment())
|
if self.environment_api.is_defined(mapping.name_for_environment()):
|
||||||
if env_value:
|
result[name] = self.environment_api.get(mapping.name_for_environment())
|
||||||
result[name] = env_value
|
|
||||||
else:
|
else:
|
||||||
if mapping.gopass_type() == GopassType.FIELD:
|
if mapping.gopass_type() == GopassType.FIELD:
|
||||||
result[name] = self.credentials_api.gopass_field_from_path(
|
result[name] = self.credentials_api.gopass_field_from_path(
|
||||||
|
|
|
@ -36,6 +36,8 @@ class Aws(Validateable, CredentialMappingDefault):
|
||||||
result = {}
|
result = {}
|
||||||
if self.aws_as_backend:
|
if self.aws_as_backend:
|
||||||
result = {
|
result = {
|
||||||
|
"access_key": self.aws_access_key,
|
||||||
|
"secret_key": self.aws_secret_key,
|
||||||
"bucket": self.aws_bucket,
|
"bucket": self.aws_bucket,
|
||||||
"key": self.__bucket_key__(),
|
"key": self.__bucket_key__(),
|
||||||
"region": self.aws_region,
|
"region": self.aws_region,
|
||||||
|
|
|
@ -20,6 +20,14 @@ CONFIG_CERTMANAGER = """certmanager:
|
||||||
"""
|
"""
|
||||||
CONFIG_ECHO = """echo: $echo
|
CONFIG_ECHO = """echo: $echo
|
||||||
"""
|
"""
|
||||||
|
CONFIG_HETZNER_CSI = """hetzner:
|
||||||
|
hcloudApiToken:
|
||||||
|
source: "PLAIN" # PLAIN, GOPASS or PROMPT
|
||||||
|
parameter: $hcloud_api # the api key for the hetzner cloud
|
||||||
|
encryptionPassphrase:
|
||||||
|
source: "PLAIN" # PLAIN, GOPASS or PROMPT
|
||||||
|
parameter: $encryption # the encryption passphrase for created volumes
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class K3s(Validateable):
|
class K3s(Validateable):
|
||||||
|
@ -28,8 +36,11 @@ class K3s(Validateable):
|
||||||
self.k3s_letsencrypt_email = inp.get("k3s_letsencrypt_email")
|
self.k3s_letsencrypt_email = inp.get("k3s_letsencrypt_email")
|
||||||
self.k3s_letsencrypt_endpoint = inp.get("k3s_letsencrypt_endpoint", "staging")
|
self.k3s_letsencrypt_endpoint = inp.get("k3s_letsencrypt_endpoint", "staging")
|
||||||
self.k3s_app_filename_to_provision = inp.get("k3s_app_filename_to_provision")
|
self.k3s_app_filename_to_provision = inp.get("k3s_app_filename_to_provision")
|
||||||
self.k3s_enable_echo = inp.get("k3s_enable_echo", "false")
|
self.k3s_enable_echo = inp.get("k3s_enable_echo", None)
|
||||||
self.k3s_provs_template = inp.get("k3s_provs_template", None)
|
self.k3s_provs_template = inp.get("k3s_provs_template", None)
|
||||||
|
self.k3s_enable_hetzner_csi = inp.get("k3s_enable_hetzner_csi", False)
|
||||||
|
self.k3s_hetzner_api_token = inp.get("k3s_hetzner_api_token", None)
|
||||||
|
self.k3s_hetzner_encryption_passphrase = inp.get("k3s_hetzner_encryption_passphrase", None)
|
||||||
self.provision_dns: Optional[DnsRecord] = None
|
self.provision_dns: Optional[DnsRecord] = None
|
||||||
|
|
||||||
def validate(self) -> List[str]:
|
def validate(self) -> List[str]:
|
||||||
|
@ -37,6 +48,9 @@ class K3s(Validateable):
|
||||||
result += self.__validate_is_not_empty__("k3s_letsencrypt_email")
|
result += self.__validate_is_not_empty__("k3s_letsencrypt_email")
|
||||||
result += self.__validate_is_not_empty__("k3s_letsencrypt_endpoint")
|
result += self.__validate_is_not_empty__("k3s_letsencrypt_endpoint")
|
||||||
result += self.__validate_is_not_empty__("k3s_app_filename_to_provision")
|
result += self.__validate_is_not_empty__("k3s_app_filename_to_provision")
|
||||||
|
if self.k3s_enable_hetzner_csi:
|
||||||
|
result += self.__validate_is_not_empty__("k3s_hetzner_api_token")
|
||||||
|
result += self.__validate_is_not_empty__("k3s_hetzner_encryption_passphrase")
|
||||||
if self.provision_dns:
|
if self.provision_dns:
|
||||||
result += self.provision_dns.validate()
|
result += self.provision_dns.validate()
|
||||||
return result
|
return result
|
||||||
|
@ -61,6 +75,9 @@ class K3s(Validateable):
|
||||||
substitutes["letsencrypt_endpoint"] = self.k3s_letsencrypt_endpoint
|
substitutes["letsencrypt_endpoint"] = self.k3s_letsencrypt_endpoint
|
||||||
if self.k3s_enable_echo is not None:
|
if self.k3s_enable_echo is not None:
|
||||||
substitutes["echo"] = self.k3s_enable_echo
|
substitutes["echo"] = self.k3s_enable_echo
|
||||||
|
if self.k3s_enable_hetzner_csi:
|
||||||
|
substitutes["hcloud_api"] = self.k3s_hetzner_api_token
|
||||||
|
substitutes["encryption"] = self.k3s_hetzner_encryption_passphrase
|
||||||
return self.__config_template__().substitute(substitutes)
|
return self.__config_template__().substitute(substitutes)
|
||||||
|
|
||||||
def command(self, devops: Devops):
|
def command(self, devops: Devops):
|
||||||
|
@ -69,7 +86,7 @@ class K3s(Validateable):
|
||||||
cmd = [
|
cmd = [
|
||||||
"provs-server.jar",
|
"provs-server.jar",
|
||||||
"k3s",
|
"k3s",
|
||||||
f"{self.k3s_provision_user}@{self.provision_dns.fqdn}",
|
f"{self.k3s_provision_user}@{self.provision_dns.ip()}",
|
||||||
"-c",
|
"-c",
|
||||||
f"{devops.build_path()}/out_k3sServerConfig.yaml",
|
f"{devops.build_path()}/out_k3sServerConfig.yaml",
|
||||||
"-a",
|
"-a",
|
||||||
|
@ -89,4 +106,6 @@ class K3s(Validateable):
|
||||||
template_text += CONFIG_IPV4
|
template_text += CONFIG_IPV4
|
||||||
if self.provision_dns.ipv6 is not None:
|
if self.provision_dns.ipv6 is not None:
|
||||||
template_text += CONFIG_IPV6
|
template_text += CONFIG_IPV6
|
||||||
|
if self.k3s_enable_hetzner_csi:
|
||||||
|
template_text += CONFIG_HETZNER_CSI
|
||||||
return Template(template_text)
|
return Template(template_text)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Optional, List
|
from typing import Optional, List, Dict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from .common import (
|
from .common import (
|
||||||
Validateable,
|
Validateable,
|
||||||
|
@ -7,6 +7,9 @@ from .common import (
|
||||||
from .version import (
|
from .version import (
|
||||||
Version,
|
Version,
|
||||||
)
|
)
|
||||||
|
from .artifact import (
|
||||||
|
Artifact,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Release(Validateable):
|
class Release(Validateable):
|
||||||
|
@ -21,6 +24,14 @@ class Release(Validateable):
|
||||||
"release_secondary_build_files", []
|
"release_secondary_build_files", []
|
||||||
)
|
)
|
||||||
self.version = version
|
self.version = version
|
||||||
|
self.release_tag_prefix = inp.get("release_tag_prefix", "")
|
||||||
|
self.release_artifact_server_url = inp.get("release_artifact_server_url")
|
||||||
|
self.release_organisation = inp.get("release_organisation")
|
||||||
|
self.release_repository_name = inp.get("release_repository_name")
|
||||||
|
self.release_artifact_token = inp.get("release_artifact_token")
|
||||||
|
self.release_artifacts = []
|
||||||
|
for a in inp.get("release_artifacts", []):
|
||||||
|
self.release_artifacts.append(Artifact(a))
|
||||||
|
|
||||||
def update_release_type(self, release_type: ReleaseType):
|
def update_release_type(self, release_type: ReleaseType):
|
||||||
self.release_type = release_type
|
self.release_type = release_type
|
||||||
|
@ -53,10 +64,44 @@ class Release(Validateable):
|
||||||
and self.release_type != ReleaseType.NONE
|
and self.release_type != ReleaseType.NONE
|
||||||
and self.release_main_branch != self.release_current_branch
|
and self.release_main_branch != self.release_current_branch
|
||||||
):
|
):
|
||||||
result.append(f"Releases are allowed only on {self.release_main_branch}")
|
result.append(
|
||||||
|
f"Releases are allowed only on {self.release_main_branch}"
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def validate_for_artifact(self):
|
||||||
|
result = []
|
||||||
|
result += self.__validate_is_not_empty__("release_artifact_server_url")
|
||||||
|
result += self.__validate_is_not_empty__("release_organisation")
|
||||||
|
result += self.__validate_is_not_empty__("release_repository_name")
|
||||||
|
result += self.__validate_is_not_empty__("release_artifact_token")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def build_files(self) -> List[str]:
|
def build_files(self) -> List[str]:
|
||||||
result = [self.release_primary_build_file]
|
result = [self.release_primary_build_file]
|
||||||
result += self.release_secondary_build_files
|
result += self.release_secondary_build_files
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def forgejo_release_api_endpoint(self) -> str:
|
||||||
|
validation = self.validate_for_artifact()
|
||||||
|
if validation != []:
|
||||||
|
raise RuntimeError(f"not valid for creating artifacts: {validation}")
|
||||||
|
|
||||||
|
server_url = self.release_artifact_server_url.removeprefix("/").removesuffix(
|
||||||
|
"/"
|
||||||
|
)
|
||||||
|
organisation = self.release_organisation.removeprefix("/").removesuffix("/")
|
||||||
|
repository = self.release_repository_name.removeprefix("/").removesuffix("/")
|
||||||
|
return f"{server_url}/api/v1/repos/{organisation}/{repository}/releases"
|
||||||
|
|
||||||
|
def forgejo_release_asset_api_endpoint(self, release_id: int) -> str:
|
||||||
|
return f"{self.forgejo_release_api_endpoint()}/{release_id}/assets"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_mapping_default(cls) -> List[Dict[str, str]]:
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"gopass_path": "server/meissa/repo/buero-rw",
|
||||||
|
"name": "release_artifact_token",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -32,12 +32,6 @@ class Version(Validateable):
|
||||||
self.snapshot_suffix = snapshot_suffix
|
self.snapshot_suffix = snapshot_suffix
|
||||||
self.default_snapshot_suffix = default_snapshot_suffix
|
self.default_snapshot_suffix = default_snapshot_suffix
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return other and self.to_string() == other.to_string()
|
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
|
||||||
return self.to_string().__hash__()
|
|
||||||
|
|
||||||
def is_snapshot(self):
|
def is_snapshot(self):
|
||||||
return self.snapshot_suffix is not None
|
return self.snapshot_suffix is not None
|
||||||
|
|
||||||
|
@ -139,3 +133,9 @@ class Version(Validateable):
|
||||||
snapshot_suffix=None,
|
snapshot_suffix=None,
|
||||||
version_str=None,
|
version_str=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return other and self.to_string() == other.to_string()
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return self.to_string().__hash__()
|
||||||
|
|
|
@ -7,5 +7,6 @@ from .infrastructure import (
|
||||||
CredentialsApi,
|
CredentialsApi,
|
||||||
GitApi,
|
GitApi,
|
||||||
TerraformApi,
|
TerraformApi,
|
||||||
|
ArtifactDeploymentApi,
|
||||||
)
|
)
|
||||||
from .repository import DevopsRepository, BuildFileRepository
|
from .repository import DevopsRepository, BuildFileRepository
|
||||||
|
|
|
@ -53,37 +53,27 @@ class ImageApi:
|
||||||
self.execution_api = ExecutionApi()
|
self.execution_api = ExecutionApi()
|
||||||
|
|
||||||
def image(self, name: str, path: Path):
|
def image(self, name: str, path: Path):
|
||||||
self.execution_api.run_handled(
|
self.execution_api.execute_live(
|
||||||
f"docker build -t {name} --file {path}/image/Dockerfile {path}/image"
|
f"docker build -t {name} --file {path}/image/Dockerfile {path}/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
def drun(self, name: str):
|
def drun(self, name: str):
|
||||||
self.execution_api.run_handled(
|
self.execution_api.execute_live(
|
||||||
f'docker run -it --entrypoint="" {name} /bin/bash'
|
f'docker run -it {name} /bin/bash'
|
||||||
)
|
)
|
||||||
|
|
||||||
def dockerhub_login(self, username: str, password: str):
|
def dockerhub_login(self, username: str, password: str):
|
||||||
self.execution_api.run_handled(
|
self.execution_api.execute_secure(
|
||||||
f"docker login --username {username} --password {password}"
|
f"docker login --username {username} --password {password}",
|
||||||
|
"docker login --username ***** --password *****",
|
||||||
)
|
)
|
||||||
|
|
||||||
def dockerhub_publish(self, name: str, username: str, tag=None):
|
def dockerhub_publish(self, name: str, username: str, tag: str):
|
||||||
if tag is not None:
|
self.execution_api.execute_live(f"docker tag {name} {username}/{name}:{tag}")
|
||||||
self.execution_api.run_handled(
|
self.execution_api.execute_live(f"docker push {username}/{name}:{tag}")
|
||||||
f"docker tag {name} {username}/{name}:{tag}"
|
|
||||||
)
|
|
||||||
self.execution_api.run_handled(
|
|
||||||
f"docker push {username}/{name}:{tag}"
|
|
||||||
)
|
|
||||||
self.execution_api.run_handled(
|
|
||||||
f"docker tag {name} {username}/{name}:latest"
|
|
||||||
)
|
|
||||||
self.execution_api.run_handled(
|
|
||||||
f"docker push {username}/{name}:latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test(self, name: str, path: Path):
|
def test(self, name: str, path: Path):
|
||||||
self.execution_api.run_handled(
|
self.execution_api.execute_live(
|
||||||
f"docker build -t {name} -test --file {path}/test/Dockerfile {path}/test"
|
f"docker build -t {name} -test --file {path}/test/Dockerfile {path}/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,40 +84,58 @@ class ExecutionApi:
|
||||||
if dry_run:
|
if dry_run:
|
||||||
print(command)
|
print(command)
|
||||||
else:
|
else:
|
||||||
# output = check_output(command, encoding="UTF-8", shell=shell)
|
|
||||||
output = run(
|
|
||||||
command, encoding="UTF-8", shell=shell, stdout=PIPE, check=check
|
|
||||||
).stdout
|
|
||||||
output = output.rstrip()
|
|
||||||
return output
|
|
||||||
|
|
||||||
def execute_live(self, command, dry_run=False, shell=True):
|
|
||||||
if dry_run:
|
|
||||||
print(command)
|
|
||||||
else:
|
|
||||||
process = Popen(command, stdout=PIPE, shell=shell)
|
|
||||||
for line in iter(process.stdout.readline, b""):
|
|
||||||
print(line.decode("utf-8"), end="")
|
|
||||||
process.stdout.close()
|
|
||||||
process.wait()
|
|
||||||
|
|
||||||
def run_handled(self, command: str, shell=True, check=True):
|
|
||||||
try:
|
try:
|
||||||
run(
|
output = run(
|
||||||
command,
|
command,
|
||||||
shell=shell,
|
shell=shell,
|
||||||
check=check,
|
check=check,
|
||||||
capture_output=True,
|
stdout=PIPE,
|
||||||
text=True)
|
stderr=PIPE,
|
||||||
|
text=True,
|
||||||
|
).stdout
|
||||||
|
output = output.rstrip()
|
||||||
except CalledProcessError as exc:
|
except CalledProcessError as exc:
|
||||||
print("Command failed with code: ", exc.returncode, " and message:", exc.stderr)
|
print(
|
||||||
|
f"Command failed with code: {exc.returncode} and message: {exc.stderr}"
|
||||||
|
)
|
||||||
|
raise exc
|
||||||
|
return output
|
||||||
|
|
||||||
|
def execute_secure(
|
||||||
|
self,
|
||||||
|
command: str,
|
||||||
|
sanitized_command: str,
|
||||||
|
dry_run=False,
|
||||||
|
shell=True,
|
||||||
|
check=True,
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
output = self.execute(command, dry_run, shell, check)
|
||||||
|
return output
|
||||||
|
except CalledProcessError as exc:
|
||||||
|
sanitized_exc = exc
|
||||||
|
sanitized_exc.cmd = sanitized_command
|
||||||
|
raise sanitized_exc
|
||||||
|
|
||||||
|
def execute_live(self, command: str, dry_run=False, shell=True):
|
||||||
|
if dry_run:
|
||||||
|
print(command)
|
||||||
|
else:
|
||||||
|
process = Popen(command, shell=shell)
|
||||||
|
outs, errs = process.communicate()
|
||||||
|
while outs is not None:
|
||||||
|
stdout.buffer.write(outs)
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise RuntimeError(f"Execute live '{command}' failed with code {process.returncode}\nerrs: {errs}")
|
||||||
|
|
||||||
|
|
||||||
class EnvironmentApi:
|
class EnvironmentApi:
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
return environ.get(key)
|
return environ.get(key)
|
||||||
|
|
||||||
|
def is_defined(self, key):
|
||||||
|
return key in environ
|
||||||
|
|
||||||
|
|
||||||
class CredentialsApi:
|
class CredentialsApi:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -206,3 +214,53 @@ class GitApi:
|
||||||
|
|
||||||
class TerraformApi:
|
class TerraformApi:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArtifactDeploymentApi:
|
||||||
|
def __init__(self):
|
||||||
|
self.execution_api = ExecutionApi()
|
||||||
|
|
||||||
|
def create_forgejo_release(self, api_endpoint_url: str, tag: str, token: str):
|
||||||
|
command = (
|
||||||
|
f'curl -X "POST" "{api_endpoint_url}" '
|
||||||
|
+ ' -H "accept: application/json" -H "Content-Type: application/json"'
|
||||||
|
+ f' -d \'{{ "body": "Provides files for release {tag}", "tag_name": "{tag}"}}\''
|
||||||
|
) # noqa: E501
|
||||||
|
print(command + ' -H "Authorization: token xxxx"')
|
||||||
|
return self.execution_api.execute_secure(
|
||||||
|
command=command + f' -H "Authorization: token {token}"',
|
||||||
|
sanitized_command=command + ' -H "Authorization: token xxxx"',
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_asset_to_release(
|
||||||
|
self,
|
||||||
|
api_endpoint_url: str,
|
||||||
|
attachment: Path,
|
||||||
|
attachment_type: str,
|
||||||
|
token: str,
|
||||||
|
):
|
||||||
|
command = (
|
||||||
|
f'curl -X "POST" "{api_endpoint_url}"'
|
||||||
|
+ ' -H "accept: application/json"'
|
||||||
|
+ ' -H "Content-Type: multipart/form-data"'
|
||||||
|
+ f' -F "attachment=@{attachment};type={attachment_type}"'
|
||||||
|
) # noqa: E501
|
||||||
|
print(command + ' -H "Authorization: token xxxx"')
|
||||||
|
return self.execution_api.execute_secure(
|
||||||
|
command=command + f' -H "Authorization: token {token}"',
|
||||||
|
sanitized_command=command + ' -H "Authorization: token xxxx"',
|
||||||
|
)
|
||||||
|
|
||||||
|
def calculate_sha256(self, path: Path):
|
||||||
|
shasum = f"{path}.sha256"
|
||||||
|
self.execution_api.execute(
|
||||||
|
f"sha256sum {path} > {shasum}",
|
||||||
|
)
|
||||||
|
return shasum
|
||||||
|
|
||||||
|
def calculate_sha512(self, path: Path):
|
||||||
|
shasum = f"{path}.sha512"
|
||||||
|
self.execution_api.execute(
|
||||||
|
f"sha512sum {path} > {shasum}",
|
||||||
|
)
|
||||||
|
return shasum
|
||||||
|
|
|
@ -26,3 +26,8 @@ class ReleaseMixin(DevopsBuild):
|
||||||
devops = self.devops_repo.get_devops(self.project)
|
devops = self.devops_repo.get_devops(self.project)
|
||||||
release = devops.mixins[MixinType.RELEASE]
|
release = devops.mixins[MixinType.RELEASE]
|
||||||
self.release_service.tag_bump_and_push_release(release)
|
self.release_service.tag_bump_and_push_release(release)
|
||||||
|
|
||||||
|
def publish_artifacts(self):
|
||||||
|
devops = self.devops_repo.get_devops(self.project)
|
||||||
|
release = devops.mixins[MixinType.RELEASE]
|
||||||
|
self.release_service.publish_artifacts(release)
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
#
|
||||||
|
#deprecated, we recommend to use install_functions_debian.sh instead. We will going to remove install_functions.sh in a future release.
|
||||||
|
#
|
||||||
function upgradeSystem() {
|
function upgradeSystem() {
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
{
|
||||||
apt-get update > /dev/null
|
apt-get update
|
||||||
apt-get -y install apt-utils > /dev/null
|
apt-get -qqy upgrade
|
||||||
apt-get -qqy dist-upgrade > /dev/null
|
} > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanupDocker() {
|
function cleanupDocker() {
|
||||||
|
|
21
src/main/resources/docker/image/resources/install_functions_alpine.sh
Executable file
21
src/main/resources/docker/image/resources/install_functions_alpine.sh
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
function upgradeSystem() {
|
||||||
|
apk -U upgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupDocker() {
|
||||||
|
rm -f /root/.ssh/authorized_keys
|
||||||
|
rm -f /root/.ssh/authorized_keys2
|
||||||
|
|
||||||
|
apk cache clean
|
||||||
|
|
||||||
|
rm -rf /tmp/*
|
||||||
|
|
||||||
|
find /var/cache -type f -exec rm -rf {} \;
|
||||||
|
find /var/log/ -name '*.log' -exec rm -f {} \;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupAmi() {
|
||||||
|
rm -f /home/ubuntu/.ssh/authorized_keys
|
||||||
|
rm -f /home/ubuntu/.ssh/authorized_keys2
|
||||||
|
cleanupDocker
|
||||||
|
}
|
25
src/main/resources/docker/image/resources/install_functions_debian.sh
Executable file
25
src/main/resources/docker/image/resources/install_functions_debian.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
function upgradeSystem() {
|
||||||
|
apt-get update
|
||||||
|
apt-get -qqy upgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupDocker() {
|
||||||
|
rm -f /root/.ssh/authorized_keys
|
||||||
|
rm -f /root/.ssh/authorized_keys2
|
||||||
|
|
||||||
|
apt-get clean
|
||||||
|
apt-get -qqy autoremove --purge
|
||||||
|
apt-get -qqy autoclean
|
||||||
|
rm -rf /var/lib/apt/lists/
|
||||||
|
|
||||||
|
rm -rf /tmp/*
|
||||||
|
|
||||||
|
find /var/cache -type f -exec rm -rf {} \;
|
||||||
|
find /var/log/ -name '*.log' -exec rm -f {} \;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupAmi() {
|
||||||
|
rm -f /home/ubuntu/.ssh/authorized_keys
|
||||||
|
rm -f /home/ubuntu/.ssh/authorized_keys2
|
||||||
|
cleanupDocker
|
||||||
|
}
|
|
@ -7,12 +7,16 @@ from src.main.python.ddadevops.domain import (
|
||||||
from src.test.python.domain.helper import (
|
from src.test.python.domain.helper import (
|
||||||
BuildFileRepositoryMock,
|
BuildFileRepositoryMock,
|
||||||
GitApiMock,
|
GitApiMock,
|
||||||
|
ArtifactDeploymentApiMock,
|
||||||
build_devops,
|
build_devops,
|
||||||
)
|
)
|
||||||
from src.main.python.ddadevops.application import ReleaseService
|
from src.main.python.ddadevops.application import ReleaseService
|
||||||
|
|
||||||
def test_sould_update_release_type():
|
|
||||||
sut = ReleaseService(GitApiMock(), BuildFileRepositoryMock("build.py"))
|
def test_should_update_release_type():
|
||||||
|
sut = ReleaseService(
|
||||||
|
GitApiMock(), ArtifactDeploymentApiMock(), BuildFileRepositoryMock("build.py")
|
||||||
|
)
|
||||||
devops = build_devops({})
|
devops = build_devops({})
|
||||||
release = devops.mixins[MixinType.RELEASE]
|
release = devops.mixins[MixinType.RELEASE]
|
||||||
sut.update_release_type(release, "MAJOR")
|
sut.update_release_type(release, "MAJOR")
|
||||||
|
@ -20,3 +24,40 @@ def test_sould_update_release_type():
|
||||||
|
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
sut.update_release_type(release, "NOT_EXISTING")
|
sut.update_release_type(release, "NOT_EXISTING")
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_publish_artifacts():
|
||||||
|
mock = ArtifactDeploymentApiMock(release='{"id": 2345}')
|
||||||
|
sut = ReleaseService(GitApiMock(), mock, BuildFileRepositoryMock())
|
||||||
|
devops = build_devops(
|
||||||
|
{
|
||||||
|
"release_artifacts": ["target/art"],
|
||||||
|
"release_artifact_server_url": "http://repo.test/",
|
||||||
|
"release_organisation": "orga",
|
||||||
|
"release_repository_name": "repo",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
release = devops.mixins[MixinType.RELEASE]
|
||||||
|
sut.publish_artifacts(release)
|
||||||
|
assert "http://repo.test/api/v1/repos/orga/repo/releases/2345/assets" == mock.add_asset_to_release_api_endpoint
|
||||||
|
|
||||||
|
def test_should_throw_exception_if_there_was_an_error_in_publish_artifacts():
|
||||||
|
devops = build_devops(
|
||||||
|
{
|
||||||
|
"release_artifacts": ["target/art"],
|
||||||
|
"release_artifact_server_url": "http://repo.test/",
|
||||||
|
"release_organisation": "orga",
|
||||||
|
"release_repository_name": "repo",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
release = devops.mixins[MixinType.RELEASE]
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
mock = ArtifactDeploymentApiMock(release='')
|
||||||
|
sut = ReleaseService(GitApiMock(), mock, BuildFileRepositoryMock())
|
||||||
|
sut.publish_artifacts(release)
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
mock = ArtifactDeploymentApiMock(release='{"message": "there was an error", "url":"some-url"}')
|
||||||
|
sut = ReleaseService(GitApiMock(), mock, BuildFileRepositoryMock())
|
||||||
|
sut.publish_artifacts(release)
|
||||||
|
|
|
@ -53,6 +53,11 @@ def devops_config(overrides: dict) -> dict:
|
||||||
"release_current_branch": "my_feature",
|
"release_current_branch": "my_feature",
|
||||||
"release_primary_build_file": "./package.json",
|
"release_primary_build_file": "./package.json",
|
||||||
"release_secondary_build_file": [],
|
"release_secondary_build_file": [],
|
||||||
|
"release_artifacts": [],
|
||||||
|
"release_artifact_token": "release_artifact_token",
|
||||||
|
"release_artifact_server_url": None,
|
||||||
|
"release_organisation": None,
|
||||||
|
"release_repository_name": None,
|
||||||
"credentials_mappings": [
|
"credentials_mappings": [
|
||||||
{
|
{
|
||||||
"gopass_path": "a/path",
|
"gopass_path": "a/path",
|
||||||
|
@ -99,6 +104,9 @@ class EnvironmentApiMock:
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
return self.mappings.get(key, None)
|
return self.mappings.get(key, None)
|
||||||
|
|
||||||
|
def is_defined(self, key):
|
||||||
|
return key in self.mappings
|
||||||
|
|
||||||
|
|
||||||
class CredentialsApiMock:
|
class CredentialsApiMock:
|
||||||
def __init__(self, mappings):
|
def __init__(self, mappings):
|
||||||
|
@ -148,5 +156,33 @@ class GitApiMock:
|
||||||
def push(self):
|
def push(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def push_follow_tags(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def checkout(self, branch: str):
|
def checkout(self, branch: str):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArtifactDeploymentApiMock:
|
||||||
|
def __init__(self, release=""):
|
||||||
|
self.release = release
|
||||||
|
self.create_forgejo_release_count = 0
|
||||||
|
self.add_asset_to_release_count = 0
|
||||||
|
self.add_asset_to_release_api_endpoint = ""
|
||||||
|
|
||||||
|
def create_forgejo_release(self, api_endpoint: str, tag: str, token: str):
|
||||||
|
self.create_forgejo_release_count += 1
|
||||||
|
return self.release
|
||||||
|
|
||||||
|
def add_asset_to_release(
|
||||||
|
self, api_endpoint: str, attachment: str, attachment_type: str, token: str
|
||||||
|
):
|
||||||
|
self.add_asset_to_release_api_endpoint = api_endpoint
|
||||||
|
self.add_asset_to_release_count += 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
def calculate_sha256(self, path: Path):
|
||||||
|
return f"{path}.sha256"
|
||||||
|
|
||||||
|
def calculate_sha512(self, path: Path):
|
||||||
|
return f"{path}.sha512"
|
||||||
|
|
32
src/test/python/domain/test_artifact.py
Normal file
32
src/test/python/domain/test_artifact.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import pytest
|
||||||
|
from pybuilder.core import Project
|
||||||
|
from pathlib import Path
|
||||||
|
from src.main.python.ddadevops.domain import (
|
||||||
|
Validateable,
|
||||||
|
DnsRecord,
|
||||||
|
Devops,
|
||||||
|
BuildType,
|
||||||
|
MixinType,
|
||||||
|
Artifact,
|
||||||
|
Image,
|
||||||
|
)
|
||||||
|
from .helper import build_devops, devops_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_validate_release():
|
||||||
|
sut = Artifact("x")
|
||||||
|
assert sut.is_valid()
|
||||||
|
|
||||||
|
sut = Artifact(None)
|
||||||
|
assert not sut.is_valid()
|
||||||
|
|
||||||
|
def test_should_calculate_type():
|
||||||
|
sut = Artifact("x.jar")
|
||||||
|
assert "application/x-java-archive" == sut.type()
|
||||||
|
|
||||||
|
sut = Artifact("x.js")
|
||||||
|
assert "application/x-javascript" == sut.type()
|
||||||
|
|
||||||
|
sut = Artifact("x.jar.sha256")
|
||||||
|
assert "text/plain" == sut.type()
|
||||||
|
|
|
@ -7,7 +7,7 @@ from src.main.python.ddadevops.domain import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_sould_validate_build_file():
|
def test_should_validate_build_file():
|
||||||
sut = BuildFile(Path("./project.clj"), "content")
|
sut = BuildFile(Path("./project.clj"), "content")
|
||||||
assert sut.is_valid()
|
assert sut.is_valid()
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ def test_sould_validate_build_file():
|
||||||
assert not sut.is_valid()
|
assert not sut.is_valid()
|
||||||
|
|
||||||
|
|
||||||
def test_sould_calculate_build_type():
|
def test_should_calculate_build_type():
|
||||||
sut = BuildFile(Path("./project.clj"), "content")
|
sut = BuildFile(Path("./project.clj"), "content")
|
||||||
assert sut.build_file_type() == BuildFileType.JAVA_CLOJURE
|
assert sut.build_file_type() == BuildFileType.JAVA_CLOJURE
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ def test_sould_calculate_build_type():
|
||||||
assert sut.build_file_type() == BuildFileType.JS
|
assert sut.build_file_type() == BuildFileType.JS
|
||||||
|
|
||||||
|
|
||||||
def test_sould_parse_and_set_js():
|
def test_should_parse_and_set_js():
|
||||||
sut = BuildFile(
|
sut = BuildFile(
|
||||||
Path("./package.json"),
|
Path("./package.json"),
|
||||||
"""
|
"""
|
||||||
|
@ -77,7 +77,7 @@ def test_sould_parse_and_set_js():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_sould_parse_and_set_version_for_gradle():
|
def test_should_parse_and_set_version_for_gradle():
|
||||||
sut = BuildFile(
|
sut = BuildFile(
|
||||||
Path("./build.gradle"),
|
Path("./build.gradle"),
|
||||||
"""
|
"""
|
||||||
|
@ -97,7 +97,7 @@ version = "1.1.5-SNAPSHOT"
|
||||||
assert '\nversion = "2.0.0"\n' == sut.content
|
assert '\nversion = "2.0.0"\n' == sut.content
|
||||||
|
|
||||||
|
|
||||||
def test_sould_parse_and_set_version_for_py():
|
def test_should_parse_and_set_version_for_py():
|
||||||
sut = BuildFile(
|
sut = BuildFile(
|
||||||
Path("./build.py"),
|
Path("./build.py"),
|
||||||
"""
|
"""
|
||||||
|
@ -143,7 +143,7 @@ version = "1.1.5-SNAPSHOT"
|
||||||
assert '\nversion = "2.0.0"\n' == sut.content
|
assert '\nversion = "2.0.0"\n' == sut.content
|
||||||
|
|
||||||
|
|
||||||
def test_sould_parse_and_set_version_for_clj():
|
def test_should_parse_and_set_version_for_clj():
|
||||||
sut = BuildFile(
|
sut = BuildFile(
|
||||||
Path("./project.clj"),
|
Path("./project.clj"),
|
||||||
"""
|
"""
|
||||||
|
@ -182,3 +182,71 @@ def test_sould_parse_and_set_version_for_clj():
|
||||||
'\n(defproject org.domaindrivenarchitecture/c4k-jira "2.0.0"\n:dependencies [[org.clojure/clojure "1.11.0"]]\n)\n '
|
'\n(defproject org.domaindrivenarchitecture/c4k-jira "2.0.0"\n:dependencies [[org.clojure/clojure "1.11.0"]]\n)\n '
|
||||||
== sut.content
|
== sut.content
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_should_parse_and_set_version_for_clj_edn():
|
||||||
|
sut = BuildFile(
|
||||||
|
Path("./deps.edn"),
|
||||||
|
"""
|
||||||
|
{:project {:name org.domaindrivenarchitecture/dda-backup
|
||||||
|
:version "1.1.5-SNAPSHOT"}
|
||||||
|
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
assert sut.get_version() == Version.from_str("1.1.5-SNAPSHOT", "SNAPSHOT")
|
||||||
|
|
||||||
|
sut = BuildFile(
|
||||||
|
Path("./deps.edn"),
|
||||||
|
"""
|
||||||
|
{:project {:name org.domaindrivenarchitecture/dda-backup
|
||||||
|
:version "1.1.5-SNAPSHOT"}
|
||||||
|
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
sut.set_version(Version.from_str("1.1.5-SNAPSHOT", "SNAPSHOT").create_major())
|
||||||
|
assert (
|
||||||
|
'\n{:project {:name org.domaindrivenarchitecture/dda-backup\n :version "2.0.0"}\n\n}\n'
|
||||||
|
== sut.content
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_throw_for_clj_wrong_version():
|
||||||
|
sut = BuildFile(
|
||||||
|
Path("./project.clj"),
|
||||||
|
"""
|
||||||
|
(defproject org.domaindrivenarchitecture/c4k-jira "1.1.5-Snapshot"
|
||||||
|
:description "jira c4k-installation package"
|
||||||
|
:url "https://domaindrivenarchitecture.org"
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
sut.get_version()
|
||||||
|
|
||||||
|
def test_should_ignore_first_version_for_py():
|
||||||
|
sut = BuildFile(
|
||||||
|
Path("./build.py"),
|
||||||
|
"""
|
||||||
|
from pybuilder.core import init, use_plugin, Author
|
||||||
|
use_plugin("python.core")
|
||||||
|
|
||||||
|
name = "ddadevops"
|
||||||
|
project_version = "0.0.2-dev1"
|
||||||
|
version = "1.1.5-dev12"
|
||||||
|
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
assert sut.get_version() == Version.from_str("1.1.5-dev12", "dev")
|
||||||
|
|
||||||
|
def test_should_ignore_first_version_for_gradle():
|
||||||
|
sut = BuildFile(
|
||||||
|
Path("./build.gradle"),
|
||||||
|
"""
|
||||||
|
kotlin_version = "3.3.3"
|
||||||
|
version = "1.1.5-SNAPSHOT"
|
||||||
|
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
assert sut.get_version() == Version.from_str("1.1.5-SNAPSHOT", "SNAPSHOT")
|
|
@ -4,10 +4,11 @@ from src.main.python.ddadevops.domain import (
|
||||||
Version,
|
Version,
|
||||||
BuildType,
|
BuildType,
|
||||||
MixinType,
|
MixinType,
|
||||||
|
Artifact,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_devops_factory():
|
def test_devops_creation():
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
DevopsFactory().build_devops({"build_types": ["NOTEXISTING"]})
|
DevopsFactory().build_devops({"build_types": ["NOTEXISTING"]})
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ def test_devops_factory():
|
||||||
assert sut is not None
|
assert sut is not None
|
||||||
assert sut.specialized_builds[BuildType.C4K] is not None
|
assert sut.specialized_builds[BuildType.C4K] is not None
|
||||||
|
|
||||||
|
def test_release_devops_creation():
|
||||||
sut = DevopsFactory().build_devops(
|
sut = DevopsFactory().build_devops(
|
||||||
{
|
{
|
||||||
"stage": "test",
|
"stage": "test",
|
||||||
|
@ -66,3 +68,32 @@ def test_devops_factory():
|
||||||
)
|
)
|
||||||
assert sut is not None
|
assert sut is not None
|
||||||
assert sut.mixins[MixinType.RELEASE] is not None
|
assert sut.mixins[MixinType.RELEASE] is not None
|
||||||
|
|
||||||
|
sut = DevopsFactory().build_devops(
|
||||||
|
{
|
||||||
|
"stage": "test",
|
||||||
|
"name": "mybuild",
|
||||||
|
"module": "test_image",
|
||||||
|
"project_root_path": "../../..",
|
||||||
|
"build_types": [],
|
||||||
|
"mixin_types": ["RELEASE"],
|
||||||
|
"release_main_branch": "main",
|
||||||
|
"release_current_branch": "my_feature",
|
||||||
|
"release_config_file": "project.clj",
|
||||||
|
"release_artifacts": ["x.jar"],
|
||||||
|
"release_artifact_token": "y",
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": "meissa",
|
||||||
|
"release_repository_name": "provs",
|
||||||
|
},
|
||||||
|
Version.from_str("1.0.0", "SNAPSHOT"),
|
||||||
|
)
|
||||||
|
|
||||||
|
release = sut.mixins[MixinType.RELEASE]
|
||||||
|
assert release is not None
|
||||||
|
assert Artifact("x.jar") == release.release_artifacts[0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_on_merge_input_should_win():
|
||||||
|
sut = DevopsFactory()
|
||||||
|
assert {'tag': 'inp'} == sut.merge(inp = {'tag': 'inp'}, context = {'tag': 'context'}, authorization={})
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
from pybuilder.core import Project
|
from pybuilder.core import Project
|
||||||
import logging
|
|
||||||
from subprocess import Popen, PIPE, run
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from src.main.python.ddadevops.domain import (
|
from src.main.python.ddadevops.domain import (
|
||||||
BuildType,
|
BuildType,
|
||||||
|
@ -14,3 +12,16 @@ def test_devops_build_commons_path():
|
||||||
assert image is not None
|
assert image is not None
|
||||||
assert image.is_valid()
|
assert image.is_valid()
|
||||||
assert "docker/" == image.build_commons_path()
|
assert "docker/" == image.build_commons_path()
|
||||||
|
|
||||||
|
def test_should_calculate_image_name():
|
||||||
|
sut = build_devops({})
|
||||||
|
image = sut.specialized_builds[BuildType.IMAGE]
|
||||||
|
assert "name" == image.image_name()
|
||||||
|
|
||||||
|
sut = build_devops({'image_naming': "NAME_ONLY"})
|
||||||
|
image = sut.specialized_builds[BuildType.IMAGE]
|
||||||
|
assert "name" == image.image_name()
|
||||||
|
|
||||||
|
sut = build_devops({'image_naming': "NAME_AND_MODULE"})
|
||||||
|
image = sut.specialized_builds[BuildType.IMAGE]
|
||||||
|
assert "name-module" == image.image_name()
|
||||||
|
|
|
@ -41,6 +41,8 @@ def test_should_calculate_backend_config():
|
||||||
{
|
{
|
||||||
"module": "dns_aws",
|
"module": "dns_aws",
|
||||||
"stage": "prod",
|
"stage": "prod",
|
||||||
|
"aws_access_key": "aws_access_key",
|
||||||
|
"aws_secret_key": "aws_secret_key",
|
||||||
"aws_bucket": "meissa-configuration",
|
"aws_bucket": "meissa-configuration",
|
||||||
"aws_bucket_kms_key_id": "arn:aws:kms:eu-central-1:907507348333:alias/meissa-configuration",
|
"aws_bucket_kms_key_id": "arn:aws:kms:eu-central-1:907507348333:alias/meissa-configuration",
|
||||||
"aws_region": "eu-central-1",
|
"aws_region": "eu-central-1",
|
||||||
|
@ -48,6 +50,8 @@ def test_should_calculate_backend_config():
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert {
|
assert {
|
||||||
|
"access_key": "aws_access_key",
|
||||||
|
"secret_key": "aws_secret_key",
|
||||||
"bucket": "meissa-configuration",
|
"bucket": "meissa-configuration",
|
||||||
"key": "prod/dns_aws",
|
"key": "prod/dns_aws",
|
||||||
"kms_key_id": "arn:aws:kms:eu-central-1:907507348333:alias/meissa-configuration",
|
"kms_key_id": "arn:aws:kms:eu-central-1:907507348333:alias/meissa-configuration",
|
||||||
|
|
|
@ -24,7 +24,7 @@ def test_should_calculate_command():
|
||||||
assert (
|
assert (
|
||||||
"provs-server.jar "
|
"provs-server.jar "
|
||||||
+ "k3s "
|
+ "k3s "
|
||||||
+ "k3s_provision_user@example.org "
|
+ "k3s_provision_user@::1 "
|
||||||
+ "-c "
|
+ "-c "
|
||||||
+ "root_path/target/name/module/out_k3sServerConfig.yaml "
|
+ "root_path/target/name/module/out_k3sServerConfig.yaml "
|
||||||
+ "-a "
|
+ "-a "
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import pytest
|
||||||
from pybuilder.core import Project
|
from pybuilder.core import Project
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from src.main.python.ddadevops.domain import (
|
from src.main.python.ddadevops.domain import (
|
||||||
|
@ -14,7 +15,7 @@ from src.main.python.ddadevops.domain import (
|
||||||
from .helper import build_devops, devops_config
|
from .helper import build_devops, devops_config
|
||||||
|
|
||||||
|
|
||||||
def test_sould_validate_release():
|
def test_should_validate_release():
|
||||||
sut = Release(
|
sut = Release(
|
||||||
devops_config(
|
devops_config(
|
||||||
{
|
{
|
||||||
|
@ -48,7 +49,7 @@ def test_sould_validate_release():
|
||||||
assert not sut.is_valid()
|
assert not sut.is_valid()
|
||||||
|
|
||||||
|
|
||||||
def test_sould_calculate_build_files():
|
def test_should_calculate_build_files():
|
||||||
sut = Release(
|
sut = Release(
|
||||||
devops_config(
|
devops_config(
|
||||||
{
|
{
|
||||||
|
@ -61,3 +62,74 @@ def test_sould_calculate_build_files():
|
||||||
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
||||||
)
|
)
|
||||||
assert ["project.clj", "package.json"] == sut.build_files()
|
assert ["project.clj", "package.json"] == sut.build_files()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_calculate_forgejo_release_api_endpoint():
|
||||||
|
sut = Release(
|
||||||
|
devops_config(
|
||||||
|
{
|
||||||
|
"release_artifacts": [],
|
||||||
|
"release_artifact_token": "y",
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": "meissa",
|
||||||
|
"release_repository_name": "provs",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"https://repo.prod.meissa.de/api/v1/repos/meissa/provs/releases"
|
||||||
|
== sut.forgejo_release_api_endpoint()
|
||||||
|
)
|
||||||
|
|
||||||
|
sut = Release(
|
||||||
|
devops_config(
|
||||||
|
{
|
||||||
|
"release_artifacts": ["x"],
|
||||||
|
"release_artifact_token": "y",
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de/",
|
||||||
|
"release_organisation": "/meissa/",
|
||||||
|
"release_repository_name": "provs",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"https://repo.prod.meissa.de/api/v1/repos/meissa/provs/releases"
|
||||||
|
== sut.forgejo_release_api_endpoint()
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
"/meissa/"
|
||||||
|
== sut.release_organisation
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
sut = Release(
|
||||||
|
devops_config(
|
||||||
|
{
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": None,
|
||||||
|
"release_repository_name": "provs",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
||||||
|
)
|
||||||
|
sut.forgejo_release_api_endpoint()
|
||||||
|
|
||||||
|
def test_should_calculate_forgejo_release_asset_api_endpoint():
|
||||||
|
sut = Release(
|
||||||
|
devops_config(
|
||||||
|
{
|
||||||
|
"release_artifacts": ["x"],
|
||||||
|
"release_artifact_token": "y",
|
||||||
|
"release_artifact_server_url": "https://repo.prod.meissa.de",
|
||||||
|
"release_organisation": "meissa",
|
||||||
|
"release_repository_name": "provs",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Version.from_str("1.3.1-SNAPSHOT", "SNAPSHOT"),
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"https://repo.prod.meissa.de/api/v1/repos/meissa/provs/releases/123/assets"
|
||||||
|
== sut.forgejo_release_asset_api_endpoint(123)
|
||||||
|
)
|
||||||
|
|
|
@ -5,7 +5,9 @@ from pybuilder.core import Project
|
||||||
|
|
||||||
from src.main.python.ddadevops.release_mixin import ReleaseMixin
|
from src.main.python.ddadevops.release_mixin import ReleaseMixin
|
||||||
from src.main.python.ddadevops.domain import Devops, Release
|
from src.main.python.ddadevops.domain import Devops, Release
|
||||||
from .domain.helper import devops_config
|
from src.main.python.ddadevops.application import ReleaseService
|
||||||
|
from src.main.python.ddadevops.infrastructure import BuildFileRepository
|
||||||
|
from .domain.helper import devops_config, GitApiMock, ArtifactDeploymentApiMock
|
||||||
from .resource_helper import copy_resource
|
from .resource_helper import copy_resource
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +16,8 @@ def test_release_mixin(tmp_path):
|
||||||
copy_resource(Path("package.json"), tmp_path)
|
copy_resource(Path("package.json"), tmp_path)
|
||||||
project = Project(str_tmp_path, name="name")
|
project = Project(str_tmp_path, name="name")
|
||||||
|
|
||||||
|
os.environ["RELEASE_ARTIFACT_TOKEN"] = "ratoken"
|
||||||
|
|
||||||
sut = ReleaseMixin(
|
sut = ReleaseMixin(
|
||||||
project,
|
project,
|
||||||
devops_config(
|
devops_config(
|
||||||
|
@ -28,3 +32,37 @@ def test_release_mixin(tmp_path):
|
||||||
|
|
||||||
sut.initialize_build_dir()
|
sut.initialize_build_dir()
|
||||||
assert sut.build_path() == f"{str_tmp_path}/target/name/release-test"
|
assert sut.build_path() == f"{str_tmp_path}/target/name/release-test"
|
||||||
|
|
||||||
|
def test_release_mixin_different_version_suffixes(tmp_path):
|
||||||
|
str_tmp_path = str(tmp_path)
|
||||||
|
copy_resource(Path("config.py"), tmp_path)
|
||||||
|
copy_resource(Path("config.gradle"), tmp_path)
|
||||||
|
|
||||||
|
project = Project(str_tmp_path, name="name")
|
||||||
|
|
||||||
|
os.environ["RELEASE_ARTIFACT_TOKEN"] = "ratoken"
|
||||||
|
|
||||||
|
sut = ReleaseMixin(
|
||||||
|
project,
|
||||||
|
devops_config(
|
||||||
|
{
|
||||||
|
"project_root_path": str_tmp_path,
|
||||||
|
"mixin_types": ["RELEASE"],
|
||||||
|
"build_types": [],
|
||||||
|
"module": "release-test",
|
||||||
|
"release_current_branch": "main",
|
||||||
|
"release_main_branch": "main",
|
||||||
|
"release_primary_build_file": "config.py",
|
||||||
|
"release_secondary_build_files": ["config.gradle"],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
sut.release_service = ReleaseService(GitApiMock(), ArtifactDeploymentApiMock(), BuildFileRepository(project.basedir))
|
||||||
|
|
||||||
|
sut.initialize_build_dir()
|
||||||
|
sut.update_release_type("PATCH")
|
||||||
|
sut.prepare_release()
|
||||||
|
sut.tag_bump_and_push_release()
|
||||||
|
|
||||||
|
assert sut.release_service.build_file_repository.get(Path("config.py")).get_version().to_string() == "3.1.5-dev"
|
||||||
|
assert sut.release_service.build_file_repository.get(Path("config.gradle")).get_version().to_string() == "3.1.5-SNAPSHOT"
|
Loading…
Reference in a new issue