Compare commits

...

10 commits

Author SHA1 Message Date
Histausse ad7b9ec602 config git before first commit 2023-06-19 09:34:35 +02:00
Histausse 99cf060e08 fix badge url 2023-05-27 18:20:07 +02:00
Histausse 48c95b975a push docker with CI 2023-05-24 12:33:11 +02:00
Histausse d6e0d933d8 push token to woodpecker 2023-05-23 14:20:32 +02:00
Histausse 721d134c6a generate new gitea token for the CI 2023-05-23 13:20:56 +02:00
Histausse 09c4d95376 add some reserche 2023-05-21 16:48:51 +02:00
Histausse 3271450011 add some research 2023-05-21 01:12:35 +02:00
Histausse d23ae91b74 add flake support 2023-05-20 23:11:08 +02:00
Histausse fc90b3fb71 Add CI config 2023-05-19 19:35:45 +02:00
Histausse 6aa251e9ec add badge 2023-05-19 18:32:16 +02:00
6 changed files with 249 additions and 18 deletions

44
TODO.md
View file

@ -1,5 +1,45 @@
# TODO: # TODO:
- add CI - publish to gitea repo: [container](https://docs.gitea.io/en-us/usage/packages/container/) [badge](https://docs.gitea.io/en-us/usage/packages/generic/)
- add flake
- use bool value for `generate_gitea_project` when the feature is available - use bool value for `generate_gitea_project` when the feature is available
### Package
```
curl -i --upload-file README.md --user "histausse:`secret-tool lookup Title 'Gitea Token'`" https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/README.md
curl https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/README.md
curl -i -X DELETE --user "histausse:`secret-tool lookup Title 'Gitea Token'`" https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/pyproject.toml
```
```
podman login -u histausse -p `secret-tool lookup Title 'Gitea Token'` git.pains-perdus.fr
podman push test_flake_poetry2nix:latest git.pains-perdus.fr/histausse/test_flake_poetry2nix:latest
```
Put secret in CI:
```
connection.request(
"POST",
f"/api/repos/{repo}/secrets",
json.dumps(
{
"name": "test_token",
"value": "loren ispum",
"image": ["test"],
"event": ["push", "tag"],
}
),
{
"Authorization": f"Bearer {API_KEY}",
"content-type": "application/json",
},
)
```
Gen badge:
```
https://github.com/smarie/python-genbadge/issues
```

View file

@ -5,12 +5,12 @@
"email": "", "email": "",
"git_user": "", "git_user": "",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}",
"gitea_url": "", "gitea_url": "https://git.pains-perdus.fr",
"project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}",
"generate_gitea_project": [ true, false ], "generate_gitea_project": [ true, false ],
"configure_ci": [ true, false ], "configure_ci": [ true, false ],
"woodpecker_gitea_user": "ci", "woodpecker_gitea_user": "ci",
"woodpecker_server": "ci.pains-perdus.fr", "woodpecker_server": "https://ci.pains-perdus.fr",
"git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git",
"version": "0.1.0", "version": "0.1.0",
"open_source_license": ["AGPL-3.0-only", "GPL-3.0-only", "MIT", "BSD-3-Clause", "ISC", "Apache-2.0", "Proprietary"], "open_source_license": ["AGPL-3.0-only", "GPL-3.0-only", "MIT", "BSD-3-Clause", "ISC", "Apache-2.0", "Proprietary"],

View file

@ -1,11 +1,28 @@
import subprocess import subprocess
import http.client
import json
import os
from base64 import b64encode
REMOVE_PATHS = [
{% if cookiecutter.open_source_license == "Proprietary" %} "LICENSE", {% endif %}
{% if cookiecutter.configure_ci == "False" %} ".woodpecker.yml", {% endif %}
]
for path in REMOVE_PATHS:
if path and os.path.exists(path):
if os.path.isdir(path):
os.rmdir(path)
else:
os.unlink(path)
subprocess.call(["poetry", "lock"])
subprocess.call(["git", "init"]) subprocess.call(["git", "init"])
subprocess.call(["git", "checkout", "-b", "main"]) subprocess.call(["git", "checkout", "-b", "main"])
subprocess.call(["git", "add", "*"]) subprocess.call(["git", "add", "*"])
subprocess.call(["git", "commit", "-m", "Initial commit"])
subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"])
subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"])
subprocess.call(["git", "commit", "-m", "Initial commit"])
# subprocess.call(["python", "-m", "venv", "venv"]) # subprocess.call(["python", "-m", "venv", "venv"])
@ -28,6 +45,69 @@ def get_secret(secret_name: str):
"please enter you gitea api token:" "please enter you gitea api token:"
) )
def get_new_gitea_token(
connection: http.client.HTTPSConnection, new_token_name: str, user: str, token: str
) -> str:
auth = b64encode(f"{user}:{token}".encode("utf-8")).decode("ascii")
connection.request(
"POST",
f"/api/v1/users/{user}/tokens",
json.dumps(
{
"name": new_token_name,
}
),
{
"Authorization": f"Basic {auth}",
"content-type": "application/json",
},
)
response = connection.getresponse()
status = response.status
if status != 201:
print(
f"\033[38;2;255;0;0mInvalid response from gitea while creating a new token: {status} ({response.reason})\033[0m"
)
print(response.read())
exit(1)
data = json.load(response)
return data["sha1"]
def push_woodpecker_secret(
connection: http.client.HTTPSConnection,
repo: str,
secret_name: str,
secret: str,
woodpecker_token: str,
images: list[str] | None = None
):
if images is None: images = []
connection.request(
"POST",
f"/api/repos/{repo}/secrets",
json.dumps(
{
"name": secret_name,
"value": secret,
"image": images,
"event": ["push", "tag"],
}
),
{
"Authorization": f"Bearer {woodpecker_token}",
"content-type": "application/json",
},
)
response = connection.getresponse()
status = response.status
if status != 200:
print(
f"\033[38;2;255;0;0mInvalid response from woodpecker when sending a new secret: {status} ({response.reason})\033[0m"
)
print(response.read())
exit(1)
response.read()
if {{cookiecutter.generate_gitea_project}}: if {{cookiecutter.generate_gitea_project}}:
try: try:
@ -35,9 +115,9 @@ if {{cookiecutter.generate_gitea_project}}:
except ModuleNotFoundError: except ModuleNotFoundError:
print("module `giteapy` is not availabled, repository not created") print("module `giteapy` is not availabled, repository not created")
exit() exit()
API_KEY = get_secret("Gitea Token") GITEA_API_KEY = get_secret("Gitea Token")
configuration = giteapy.Configuration() configuration = giteapy.Configuration()
configuration.api_key["access_token"] = API_KEY configuration.api_key["access_token"] = GITEA_API_KEY
client = giteapy.ApiClient(configuration) client = giteapy.ApiClient(configuration)
client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1" client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1"
api_instance = giteapy.UserApi(client) api_instance = giteapy.UserApi(client)
@ -48,10 +128,6 @@ if {{cookiecutter.generate_gitea_project}}:
if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}:
import http.client
# import json
api_instance = giteapy.RepositoryApi(client) api_instance = giteapy.RepositoryApi(client)
options = giteapy.AddCollaboratorOption("read") options = giteapy.AddCollaboratorOption("read")
api_instance.repo_add_collaborator( api_instance.repo_add_collaborator(
@ -60,16 +136,18 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}:
"{{ cookiecutter.woodpecker_gitea_user }}", "{{ cookiecutter.woodpecker_gitea_user }}",
body=options, body=options,
) )
connection_gitea = http.client.HTTPSConnection("git.pains-perdus.fr")
API_KEY = get_secret("Woodpecker Token") GITEA_API_KEY = get_new_gitea_token(connection_gitea, "CI {{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "{{ cookiecutter.git_user }}", GITEA_API_KEY)
WOODPECKER_API_KEY = get_secret("Woodpecker Token")
WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://") WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://")
origin = "{{ cookiecutter.git_origin }}" origin = "{{ cookiecutter.git_origin }}"
repo = "/".join(origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) repo = "/".join(origin.removesuffix(".git").split(":")[-1].split("/")[-2:])
connection = http.client.HTTPSConnection(WOODPECKER_SERVER) connection = http.client.HTTPSConnection(WOODPECKER_SERVER)
connection.request( connection.request(
"GET", "GET",
"/api/user/repos?all=true&flush=true", "/api/user/repos?all=true&flush=true",
headers={"Authorization": f"Bearer {API_KEY}"}, headers={"Authorization": f"Bearer {WOODPECKER_API_KEY}"},
) )
response = connection.getresponse() response = connection.getresponse()
status = response.status status = response.status
@ -84,7 +162,7 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}:
"POST", "POST",
f"/api/repos/{repo}", f"/api/repos/{repo}",
headers={ headers={
"Authorization": f"Bearer {API_KEY}", "Authorization": f"Bearer {WOODPECKER_API_KEY}",
"referer": f"https://{WOODPECKER_SERVER}/repo/add", "referer": f"https://{WOODPECKER_SERVER}/repo/add",
}, },
) )
@ -94,7 +172,16 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}:
print( print(
f"\033[38;2;255;0;0mInvalid response from woodpecker while linking repo: {status} ({response.reason})\033[0m" f"\033[38;2;255;0;0mInvalid response from woodpecker while linking repo: {status} ({response.reason})\033[0m"
) )
print(response.read())
exit(1) exit(1)
response.read()
push_woodpecker_secret(
connection,
repo,
"gitea_token",
GITEA_API_KEY,
WOODPECKER_API_KEY
)
if {{cookiecutter.generate_gitea_project}}: if {{cookiecutter.generate_gitea_project}}:
subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"])

View file

@ -1,5 +1,39 @@
pipeline: pipeline:
a-test-step: test:
image: debian group: test
image: python:${PYTHON_VERSION}
pull: true
environment:
- POETRY_VIRTUALENVS_IN_PROJECT=true
commands: commands:
- echo "Testing.." - pip install poetry
- poetry install
- poetry run pytest
nix:
group: test
image: nixos/nix:latest
pull: true
commands:
- nix build --experimental-features 'nix-command flakes'
- nix build -o image_link --experimental-features 'nix-command flakes' .#docker
- cp image_link image
when:
matrix:
PYTHON_VERSION: {{ cookiecutter.python_min_version}} # Still not sure about how to make flake for different python version
push_image:
image: quay.io/podman/stable:latest
pull: true
commands:
- podman login -u {{ cookiecutter.git_user }} -p $GITEA_TOKEN {{ cookiecutter.gitea_url.removeprefix('https://') }}
- podman load < image
- podman push {{ cookiecutter.project_slug }}:latest {{ cookiecutter.gitea_url.removeprefix('https://') }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}:latest
secrets: [ gitea_token ]
when:
matrix:
PYTHON_VERSION: {{ cookiecutter.python_min_version}} # Still not sure about how to make flake for different python version
matrix:
PYTHON_VERSION:
- {{ cookiecutter.python_min_version}}

View file

@ -1,16 +1,50 @@
{% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%} {% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%}
{% set repo = "/".join(cookiecutter.git_origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) %}
# {{ cookiecutter.project_name }} # {{ cookiecutter.project_name }}
{% if cookiecutter.configure_ci == "True" %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/{{ repo }}){% endif %}
{{ cookiecutter.project_short_description }} {{ cookiecutter.project_short_description }}
## Install ## Install
### With pip
This project can be installed using pip: This project can be installed using pip:
``` ```
pip install git+{{ cookiecutter.project_url }}.git pip install git+{{ cookiecutter.project_url }}.git
``` ```
### With Nix
There is a `flake.nix`, so you can clone the repo and use `nix shell` if you want.
### Docker/Podman
{% if cookiecutter.configure_ci == "True" %}
You can run this projet with docker or podman:
```
podman run --rm -it {{ cookiecutter.gitea_url.removeprefix('https://') }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}:latest {{ cookiecutter.project_slug }}
```
{% else %}
You can build a container image using nix. To build the image, in the repo, run:
```
nix build -o {{ cookiecutter.project_slug }}.img .#docker
```
You can then load the image with:
```
podman load < {{ cookiecutter.project_slug }}.img
```
{% endif %}
Notice the image is build with nix and is very minimalist.
{% if is_open_source %} {% if is_open_source %}
## License ## License

View file

@ -0,0 +1,36 @@
{
description = "{{ cookiecutter.project_short_description }}";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.poetry2nix = {
url = "github:nix-community/poetry2nix";
inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, flake-utils, poetry2nix }:
flake-utils.lib.eachDefaultSystem (system:
let
inherit (poetry2nix.legacyPackages.${system}) mkPoetryApplication;
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages = {
{{ cookiecutter.project_slug }} = mkPoetryApplication { projectDir = self; };
docker = pkgs.dockerTools.buildImage {
name = "{{ cookiecutter.project_slug }}";
tag = "latest";
copyToRoot = pkgs.buildEnv {
name = "{{ cookiecutter.project_slug }}_root_img";
paths = [ self.packages.${system}.{{ cookiecutter.project_slug }} ];
pathsToLink = [ "/bin" ];
};
};
default = self.packages.${system}.{{ cookiecutter.project_slug }};
};
devShells.default = pkgs.mkShell {
packages = [ poetry2nix.packages.${system}.poetry ];
};
});
}