This commit is contained in:
2024-05-03 12:25:20 +03:00
commit 8236ae0642
19 changed files with 452 additions and 0 deletions

4
.cargo/config.toml Normal file
View File

@ -0,0 +1,4 @@
[registries]
[registries.git_{{git-owner}}]
index = "sparse+https://git.smetan.ru/api/packages/{{git-owner}}/cargo/"

5
.env.example Normal file
View File

@ -0,0 +1,5 @@
DB_DATABASE=test_db
DB_USERNAME=user
DB_PASSWORD=pass
DB_PORT=5432
DATABASE_URL=postgres://user:pass@localhost:5432/test_db

View File

@ -0,0 +1,95 @@
name: "Build {{project-name}}"
# You must add gitea secrets and enable actions for repository:
# CRATES_TOKEN
# DOCKER_USER
# DOCKER_PASSWORD
{%- if crate_type == "bin" %}
env:
DOCKER_REGISTRY: git.smetan.ru
IMAGE_NAME: "{{git-owner}}/{{project-name}}"
IMAGE_RELEASE_TAG: latest
IMAGE_PRE_RELEASE_TAG: pre-release
{%- endif %}
on:
{%- if crate_type == "bin" %}
push:
branches:
- master
- main
{%- endif %}
release:
types:
- published
jobs:
{%- if crate_type == "bin" -%}
{% raw %}
build_docker_app:
name: Build Docker Image
runs-on: docker-ubuntu-latest
steps:
- name: Checkout sources
uses: https://github.com/actions/checkout@v4
- name: Set Image Name
run: |
echo "Event type: $GITHUB_EVENT_NAME"
if [[ $GITHUB_EVENT_NAME == 'release' ]]; then
echo "IMAGE_TAG=$DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_RELEASE_TAG" >> "$GITHUB_ENV"
else
echo "IMAGE_TAG=$DOCKER_REGISTRY/$IMAGE_NAME:$IMAGE_PRE_RELEASE_TAG" >> "$GITHUB_ENV"
fi
cat $GITHUB_ENV
- name: Build Image
run: docker build --build-arg CRATES_TOKEN=${{ secrets.CRATES_TOKEN }} --file Dockerfile --tag ${{ env.IMAGE_TAG }} .
- name: Docker Login
run: docker login --username ${{ secrets.DOCKER_USER }} --password ${{ secrets.DOCKER_PASSWORD }} ${{ env.DOCKER_REGISTRY }}
- name: Push Image
run: docker push ${{ env.IMAGE_TAG }}
- name: Docker Logout
run: docker logout ${{ env.DOCKER_REGISTRY }}
{% endraw %}
{%- endif -%}
{%- if crate_type == "lib" -%}
{% raw %}
publish_crate_version:
name: Publish new crate version
runs-on: ubuntu-latest
container:
image: git.smetan.ru/infra/ci-cargo:latest
credentials:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
steps:
- name: Checkout sources
uses: https://github.com/actions/checkout@v4
- name: Set cargo registry
run: |
cat <<"EOF" | tee ~/.cargo/config.toml
[registry]
global-credential-providers = ["cargo:token"]
EOF
- name: Set Cargo version
run: |
export VERSION=`sed 's/v//'<<<"${{ github.ref_name }}"`
echo "Set Cargo version: $VERSION"
sed -i "s/0.0.0-git/$VERSION/g" Cargo.toml
sed -i "s/0.0.0-git/$VERSION/g" Cargo.lock
- name: Publish package version
env:
{%- endraw %}
CARGO_REGISTRY: git_{{git-owner}}
{%- raw %}
run: cargo publish --registry $CARGO_REGISTRY --token "Bearer ${{ secrets.CRATES_TOKEN }}" --allow-dirty
{% endraw %}
{%- endif -%}

View File

@ -0,0 +1,122 @@
name: Validate Pull Request
# You must add gitea secrets and enable actions for repository:
# CRATES_TOKEN
# DOCKER_USER
# DOCKER_PASSWORD
# ISSUE_API_RW_TOKEN
on:
pull_request:
types:
- opened
- edited
- reopened
- synchronize
branches:
- master
- main
jobs:
{%- raw %}
validate:
name: Validate
runs-on: ubuntu-latest
container:
image: git.smetan.ru/infra/ci-cargo:latest
credentials:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
steps:
- name: Checkout sources
uses: https://github.com/actions/checkout@v4
- name: Set cargo registry
run: |
cat <<"EOF" | tee ~/.cargo/config.toml
[registry]
global-credential-providers = ["cargo:token"]
EOF
- name: Login to cargo registry
env:
{%- endraw %}
CARGO_REGISTRY: git_{{git-owner}}
{%- raw %}
run: cargo login --registry $CARGO_REGISTRY "Bearer ${{ secrets.CRATES_TOKEN }}"
- name: Cargo fmt
run: cargo fmt --all --check
- name: Cargo clippy
run: cargo clippy
{%- endraw %}
test:
{%- raw %}
name: Tests
runs-on: ubuntu-latest
container:
image: git.smetan.ru/infra/ci-cargo:latest
credentials:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
{%- endraw %}
{%- if use_postgres == true %}
services:
db:
# Docker Hub image
image: postgres:15
# Provide the password for postgres
env:
POSTGRES_DB: test_db
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
{%- endif %}
steps:
{%- raw %}
- name: Checkout sources
uses: https://github.com/actions/checkout@v4
{% endraw -%}
{%- if use_postgres == true -%}
- name: Setup .env
run: |
echo "DATABASE_URL=postgres://user:pass@db:5432/test_db" >> .env
{%- endif -%}
{%- raw %}
- name: Set cargo registry
run: |
cat <<"EOF" | tee ~/.cargo/config.toml
[registry]
global-credential-providers = ["cargo:token"]
EOF
- name: Login to cargo registry
env:
{%- endraw %}
CARGO_REGISTRY: git_{{git-owner}}
{%- raw %}
run: cargo login --registry $CARGO_REGISTRY "Bearer ${{ secrets.CRATES_TOKEN }}"
- name: Run Tests
run: |
make prepare
make test
curl --silent -X 'POST' \
'${{ github.api_url }}/repos/${{ github.repository }}/issues/${{ github.event.number }}/comments' \
-H 'accept: application/json' \
-H 'Authorization: token ${{ secrets.ISSUE_API_RW_TOKEN }}' \
-H 'Content-Type: application/json' \
-d "{\"body\":\"# Code Coverage:\n$(cat target/coverage/statistic.md)\"}"
{%- endraw %}

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
/coverage
.env

6
.rusty-hook.toml Normal file
View File

@ -0,0 +1,6 @@
[hooks]
pre-commit = "cargo check && cargo clippy && cargo fmt -- --check"
pre-push = "cargo test"
[logging]
verbose = true

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"rust-analyzer.linkedProjects": ["./Cargo.toml"],
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file"
}
}

18
Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "{{project-name}}"
description = ""
version = "0.0.0-git"
authors = ["{{authors}}"]
edition = "2021"
license-file = "LICENSE.txt"
documentation = "https://git.smetan.ru/{{git-owner}}/{{project-name}}"
homepage = "https://git.smetan.ru/{{git-owner}}/{{project-name}}"
[dependencies]
{%- if use_postgres == true %}
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }
tokio = { version = "1.36.0", features = ["rt", "macros"] }
{%- endif %}
[dev-dependencies]
rusty-hook = "0.11.2"

52
Dockerfile Normal file
View File

@ -0,0 +1,52 @@
FROM rust:latest as builder
RUN \
# Setup image building for scratch image...
apt update \
&& apt install -y musl-tools musl-dev \
&& apt-get install -y build-essential \
&& yes | apt install gcc-x86-64-linux-gnu \
# Add open ssl support
&& apt install ca-certificates \
&& update-ca-certificates \
&& apt install pkg-config libssl-dev make \
# Add our own user and group to avoid permission problems
&& addgroup --gid 131313 app \
&& adduser --uid 131313 --gid 131313 --shell /bin/false --home /app --disabled-password app \
# Prepare user data for final image
&& cat /etc/passwd | grep app > /etc/passwd_app
WORKDIR /app
COPY . .
RUN rustup toolchain install nightly \
&& rustup target add x86_64-unknown-linux-musl
# Login to Gitea
ARG CRATES_TOKEN
RUN mkdir ~/.cargo && cat <<"EOF" | tee ${CARGO_HOME}/config.toml
[registry]
global-credential-providers = ["cargo:token"]
EOF
RUN cargo login --registry git_{{git-owner}} "Bearer ${CRATES_TOKEN}"
# Build bin for scratch
ENV RUSTFLAGS='-C linker=x86_64-linux-gnu-gcc'
RUN cargo build --release --target x86_64-unknown-linux-musl
# Final image
FROM scratch
WORKDIR /app
# Copy user settings
COPY --from=builder /etc/passwd_app /etc/passwd
# Copy builded image
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/{{project-name}} ./
# Copy CA Certificates
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
USER app
CMD ["./{{project-name}}"]

2
LICENSE.txt Normal file
View File

@ -0,0 +1,2 @@
Copyright (c) {{authors}}.
All rights reserved.

16
Makefile Normal file
View File

@ -0,0 +1,16 @@
prepare-mac: prepare
brew install llvm
prepare:
rustup component add llvm-tools-preview
test:
cargo clean
mkdir -p coverage/
mkdir -p target/coverage
rm -rf coverage/*
rm -rf target/coverage/*
RUSTFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='coverage/cargo-test-%p-%m.profraw' cargo test --workspace
grcov . --binary-path ./target/debug/deps/ -s . -t lcov --branch --ignore-not-existing --ignore '../*' --ignore "/*" --ignore "*.test.rs" --excl-line '^[ \t]*///.$$' -o target/coverage/lcov.info
grcov . --binary-path ./target/debug/deps/ -s . -t markdown --branch --ignore-not-existing --ignore '../*' --ignore "/*" --ignore "*.test.rs" --excl-line '^[ \t]*///.$$' -o target/coverage/statistic.md
cat target/coverage/statistic.md

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# Template for RUST project
## Prerequisites
### Install and update RUST
https://www.rust-lang.org/tools/install
### Install cargo-generate lib
https://cargo-generate.github.io/cargo-generate/installation.html
## Create new Project from template
```bash
cargo generate -g https://git.smetan.ru/template/rust.git -n project-name --bin
```
Params:
`-g` - git path for this template
`-n` - new project name
`--bin/--lib` - binary(default) or library project. This also affects on building process: `bin` builds as Docker image, `lib` builds as Cargo package

13
cargo-generate.toml Normal file
View File

@ -0,0 +1,13 @@
[placeholders]
git-owner = { prompt = "Gitea owner or organization name", type = "string", regex = "^[A-Za-z0-9][A-Za-z0-9-]{0,38}$" }
use_postgres = { prompt = "Do you use PostgreSQL for tests?", type = "bool", default = false }
[template]
cargo_generate_version = ">=0.20.0"
ignore = ["README.md"]
[conditional.'crate_type == "lib"']
ignore = [ "src/main.rs", "Dockerfile" ]
[conditional.'use_postgres == false']
ignore = [ ".env.example", "docker-compose.yaml", "tests" ]

26
docker-compose.yaml Normal file
View File

@ -0,0 +1,26 @@
version: '3.8'
services:
db:
container_name: postgres
image: postgres:15
environment:
- POSTGRES_DB=${DB_DATABASE}
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
restart: always
ports:
- ${DB_PORT}:5432
networks:
- postgres
volumes:
- type: volume
source: db
target: /var/lib/postgresql/data
volumes:
db:
networks:
postgres:
name: postgres_network

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

40
rustfmt.toml Normal file
View File

@ -0,0 +1,40 @@
array_width = 100
attr_fn_like_width = 100
binop_separator = "Front"
blank_lines_lower_bound = 0
blank_lines_upper_bound = 1
brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine"
chain_width = 100
combine_control_expr = true
comment_width = 120
condense_wildcard_suffixes = true
edition = "2021"
empty_item_single_line = true
enum_discrim_align_threshold = 20
fn_call_width = 100
fn_params_layout = "Tall"
fn_single_line = true
force_multiline_blocks = false
format_code_in_doc_comments = true
doc_comment_code_block_width = 120
format_generated_files = true
format_macro_matchers = true
format_macro_bodies = true
format_strings = true
hard_tabs = false
imports_indent = "Visual"
imports_layout = "HorizontalVertical"
indent_style = "Block"
inline_attribute_width = 0
max_width = 120
imports_granularity = "Module"
newline_style = "Unix"
reorder_impl_items = true
reorder_imports = true
group_imports = "StdExternalCrate"
single_line_let_else_max_width = 0
spaces_around_ranges = false
struct_lit_single_line = false
tab_spaces = 2
trailing_comma = "Vertical"

11
src/lib.rs Normal file
View File

@ -0,0 +1,11 @@
pub fn main() -> &'static str { "Test it!" }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check() {
assert_eq!("Test it!", main());
}
}

5
src/main.rs Normal file
View File

@ -0,0 +1,5 @@
use {{crate_name}};
fn main() {
println!("{}", {{crate_name}}::main());
}

8
tests/pg-connection.rs Normal file
View File

@ -0,0 +1,8 @@
use sqlx::{Pool, Postgres};
#[sqlx::test]
async fn basic_test(pool: Pool<Postgres>) -> sqlx::Result<()> {
let mut conn = pool.acquire().await?;
let db_test = sqlx::query("SELECT 1").fetch_one(&mut *conn).await?;
Ok(())
}