52 Commits

Author SHA1 Message Date
cuddle-please
3ec1f98271 chore(release): 0.6.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-09 22:46:23 +00:00
5fd902f87c feat: enable commit bodies in changelog and fixes general warnings and updates (#49)
All checks were successful
continuous-integration/drone/push Build is passing
Allows commit bodies to show up in release notes, this is something I'd prefer as my releases are usually short, and I'd like to see these as I don't use pull requests as often, and often miss the context, as I don't link to commits currently.

Also fixes a lot of warnings and reintroduces failing tests, still not perfect, but better than before.
Co-authored-by: kjuulh <contact@kjuulh.io>
Co-committed-by: kjuulh <contact@kjuulh.io>
2025-01-09 23:46:07 +01:00
600d8c184c chore(deps): update rust crate serde to v1.0.217
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-28 01:28:59 +00:00
be27da1712 chore(deps): update rust crate serde to v1.0.216
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-11 05:24:41 +00:00
87e789d657 chore(deps): update rust crate tracing-subscriber to v0.3.19
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-30 01:43:37 +00:00
16710ed41b chore(deps): update rust crate tracing to v0.1.41
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-28 01:28:01 +00:00
18bd9e900a chore(deps): update rust crate serde to v1.0.215
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-11-12 01:22:22 +00:00
545e8c5476 chore(deps): update rust crate serde to v1.0.214
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-29 01:27:46 +00:00
42f23fdfac chore(deps): update rust crate serde to v1.0.213
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-23 00:28:22 +00:00
249a40f1aa chore(deps): update rust crate serde to v1.0.210
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-17 00:26:58 +00:00
c1187022f2 feat: removed tests for now
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-10-16 21:40:02 +02:00
0fc1438a4a feat: update deps
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-10-16 21:30:38 +02:00
166be0c289 feat: update
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-10 15:48:57 +02:00
cuddle-please
ff9f5e25d2 chore(release): 0.5.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore: stuff

feat: something

Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-10 15:47:28 +02:00
9ac744b39d feat: stuff
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-09 23:31:19 +02:00
9c967a0f31 feat: with rust version
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-09 23:10:12 +02:00
3878e6bc0a feat: add rust actions
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-09 22:57:01 +02:00
cuddle-please
9999fca9b0 chore(release): 0.4.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-04-08 21:08:18 +00:00
dad8fc472e feat: remove comment
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-08 23:07:51 +02:00
05ecdf5251 feat: add jq
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-08 22:52:06 +02:00
12063f7c23 feat: fix tests
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-08 22:48:30 +02:00
490130126b feat: update deps
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-04-08 22:44:14 +02:00
9201ff9294 chore(deps): update all dependencies
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-04-05 14:34:44 +00:00
477d82af55 feat: update chrono
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 21:32:40 +01:00
d94b9cbe86 feat: remove deps
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 21:19:39 +01:00
2b277ec61f something
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-30 21:17:48 +01:00
3f2642aed0 feat: without dagger
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-03-30 20:53:08 +01:00
44bc26de93 fix(deps): update rust crate futures to 0.3.30
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
2023-12-24 14:58:32 +00:00
013bf3b3dc fix(deps): update rust crate futures to 0.3.29
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
2023-10-26 15:01:40 +00:00
497ae0f19d chore(deps): update rust crate chrono to 0.4.28
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-30 20:09:36 +00:00
2dcd9d0cd1 chore(deps): update rust crate chrono to 0.4.27
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-29 14:44:14 +00:00
a0634a542b chore(deps): update rust crate clap to 4.4.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-28 17:27:34 +00:00
036998b0b9 chore(deps): update rust crate url to 2.4.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-28 10:09:28 +00:00
e92284002a chore(deps): update rust crate regex to 1.9.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-26 14:37:53 +00:00
69f64bdab2 chore(deps): update rust crate clap to 4.4.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-24 16:37:13 +00:00
f624109643 chore(deps): update rust crate reqwest to 0.11.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-23 21:11:15 +00:00
2404a14a32 chore(deps): update rust crate clap to 4.3.24
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-23 14:54:25 +00:00
9a5396a81e chore(deps): update rust crate reqwest to 0.11.19
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-21 19:23:22 +00:00
ae0a54db69 chore(deps): update rust crate clap to 4.3.23
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-18 21:35:58 +00:00
8e36f2a3ca chore(deps): update all dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-17 14:35:51 +00:00
cuddle-please
384e575758 chore(release): 0.3.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-08-13 12:23:58 +00:00
850ada11c2 chore: remove unnused arguments
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-13 14:17:30 +02:00
56d33e2ca5 chore(ci): fix release step
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-13 14:12:52 +02:00
d64a1d15dc feat(ci): with dagger-rust components
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-13 14:10:40 +02:00
c2e0b548f6 chore: add dagger-rust and dagger-cuddle-please
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-13 13:39:59 +02:00
51ca73a53b fix(git): make sure we always fail on exit code != 0
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-12 21:48:18 +02:00
675947ed1e feat: allow v in start of versions
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2023-08-08 16:15:49 +02:00
bf3593eee4 chore(deps): update rust crate clap to 4.3.21
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-08 02:23:16 +00:00
19d748702a chore(deps): update rust crate clap to 4.3.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-08 01:34:57 +00:00
4276f4529c chore(deps): update rust crate parse-changelog to 0.6.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-06 10:08:44 +00:00
d287a54cdf chore(deps): update rust crate regex to 1.9.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-05 22:31:28 +00:00
7baf51c1f2 chore(deps): update rust crate regex to 1.9.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-08-05 19:04:56 +00:00
34 changed files with 2354 additions and 4122 deletions

View File

@@ -1,170 +1,2 @@
kind: pipeline
name: default
type: docker
steps:
- name: build ci
image: rustlang/rust:nightly
volumes:
- name: ci
path: /mnt/ci
environment:
PKG_CONFIG_SYSROOT_DIR: "/"
CI_PREFIX: "/mnt/ci"
commands:
- set -e
- apt update
- apt install musl-tools pkg-config libssl-dev openssl build-essential musl-dev -y
- rustup target add x86_64-unknown-linux-musl
- cargo build --target=x86_64-unknown-linux-musl -p ci
#- cargo build -p ci
- mv target/x86_64-unknown-linux-musl/debug/ci "$CI_PREFIX/ci"
#- mv target/debug/ci $CI_PREFIX/ci
- name: load_secret
image: debian:buster-slim
volumes:
- name: ssh
path: /root/.ssh/
environment:
SSH_KEY:
from_secret: gitea_id_ed25519
commands:
- mkdir -p $HOME/.ssh/
- echo "$SSH_KEY" | base64 -d > $HOME/.ssh/id_ed25519
- name: build pr
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
- name: ci
path: /mnt/ci
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io
- ldd $CI_PREFIX
- apk add git
- cuddle x ci:pr
environment:
DOCKER_BUILDKIT: 1
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CI_PREFIX: "/mnt/ci/ci"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- pull_request
exclude:
- main
- master
depends_on:
- "load_secret"
- "build ci"
- name: build main
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
- name: ci
path: /mnt/ci
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io
- ldd $CI_PREFIX
- apk add git
- cuddle x ci:main
environment:
DOCKER_BUILDKIT: 1
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CI_PREFIX: "/mnt/ci/ci"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- push
branch:
- main
- master
exclude:
- pull_request
depends_on:
- "load_secret"
- "build ci"
- name: deploy release
image: kasperhermansen/cuddle:latest
pull: always
volumes:
- name: ssh
path: /root/.ssh/
- name: dockersock
path: /var/run
commands:
- eval `ssh-agent`
- chmod -R 600 ~/.ssh
- ssh-add
- cuddle x build:release:all
- cuddle x deploy:docs:preview
environment:
DOCKER_BUILDKIT: 1
CUDDLE_SECRETS_PROVIDER: 1password
CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci"
CUDDLE_SSH_AGENT: "true"
CUDDLE_CI: "true"
CUDDLE_PLEASE_TOKEN:
from_secret: cuddle_please_token
OP_SERVICE_ACCOUNT_TOKEN:
from_secret: op_service_account_token
when:
event:
- tag
ref:
include:
- refs/tags/v*
depends_on:
- "load_secret"
- "build ci"
services:
- name: docker
image: docker:dind
privileged: true
volumes:
- name: dockersock
path: /var/run
volumes:
- name: ssh
temp: {}
- name: dockersock
temp: {}
- name: ci
temp: {}
kind: template
load: cuddle-rust-cli-plan.yaml

View File

@@ -6,6 +6,90 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.6.0] - 2025-01-09
### Added
- enable commit bodies in changelog and fixes general warnings and updates (#49)
- removed tests for now
- update deps
- update
### Other
- *(deps)* update rust crate serde to v1.0.217
- *(deps)* update rust crate serde to v1.0.216
- *(deps)* update rust crate tracing-subscriber to v0.3.19
- *(deps)* update rust crate tracing to v0.1.41
- *(deps)* update rust crate serde to v1.0.215
- *(deps)* update rust crate serde to v1.0.214
- *(deps)* update rust crate serde to v1.0.213
- *(deps)* update rust crate serde to v1.0.210
## [0.5.0] - 2024-04-09
### Added
- stuff
- with rust version
- add rust actions
## [0.4.0] - 2024-04-08
### Added
- remove comment
- add jq
- fix tests
- update deps
- update chrono
- remove deps
- without dagger
### Fixed
- *(deps)* update rust crate futures to 0.3.30
- *(deps)* update rust crate futures to 0.3.29
### Other
- *(deps)* update all dependencies
- something
- *(deps)* update rust crate chrono to 0.4.28
- *(deps)* update rust crate chrono to 0.4.27
- *(deps)* update rust crate clap to 4.4.1
- *(deps)* update rust crate url to 2.4.1
- *(deps)* update rust crate regex to 1.9.4
- *(deps)* update rust crate clap to 4.4.0
- *(deps)* update rust crate reqwest to 0.11.20
- *(deps)* update rust crate clap to 4.3.24
- *(deps)* update rust crate reqwest to 0.11.19
- *(deps)* update rust crate clap to 4.3.23
- *(deps)* update all dependencies
## [0.3.0] - 2023-08-13
### Added
- *(ci)* with dagger-rust components
- allow v in start of versions
- *(json-edit)* added json-edit to update some json content with next global version
### Fixed
- *(git)* make sure we always fail on exit code != 0
- *(json-edit)* with actual arg instead of stupid str replace
- *(ci)* without token
- *(docs)* check fix version
- *(crate)* initial pr always included the entire changelog
- *(crate)* always prefix with 'v' when creating prs, or releases (#9)
### Other
- remove unnused arguments
- *(ci)* fix release step
- add dagger-rust and dagger-cuddle-please
- *(deps)* update rust crate clap to 4.3.21
- *(deps)* update rust crate clap to 4.3.20
- *(deps)* update rust crate parse-changelog to 0.6.2
- *(deps)* update rust crate regex to 1.9.3
- *(deps)* update rust crate regex to 1.9.2
- remove cr
- *(json-edit)* clarify errors
- *(docs)* remove 0.2 checklist
## [0.2.1] - 2023-08-04
### Docs
@@ -44,7 +128,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- add mkdocs build
- add basic version
- update with repository
- add publishable to rest
- add publish to rest
- hack get in control of log level
### Docs

2840
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,5 @@
[workspace]
members = [
"crates/cuddle-please",
"crates/cuddle-please-frontend",
"crates/cuddle-please-commands",
"crates/cuddle-please-misc",
"crates/cuddle-please-release-strategy",
"ci"
]
members = ["crates/*"]
resolver = "2"
[workspace.dependencies]
@@ -15,25 +8,30 @@ cuddle-please-frontend = { path = "crates/cuddle-please-frontend", version = "0.
cuddle-please-commands = { path = "crates/cuddle-please-commands", version = "0.1.0" }
cuddle-please-misc = { path = "crates/cuddle-please-misc", version = "0.1.0" }
cuddle-please-release-strategy = { path = "crates/cuddle-please-release-strategy", version = "0.1.0" }
cuddle-please-actions = { path = "crates/cuddle-please-actions", version = "0.1.0" }
anyhow = { version = "1.0.72" }
anyhow = { version = "1.0.81" }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
clap = { version = "4.3.19", features = ["derive", "env"] }
dotenv = { version = "0.15.0" }
url = { version = "2.4.0" }
serde_yaml = { version = "0.9.25" }
serde_json = { version = "*" }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
clap = { version = "4.5.23", features = ["derive", "env"] }
dotenvy = { version = "0.15.7" }
url = { version = "2.5.0" }
serde_yaml = { version = "0.9.34+deprecated" }
yaml-rust2 = { version = "0.8.0" }
serde = { version = "1", features = ["derive"] }
semver = "1.0.18"
semver = "1.0.22"
conventional_commit_parser = "0.9.4"
tempdir = "0.3.7"
reqwest = { version = "0.11.18" }
git-cliff-core = "1.2.0"
regex = "1.9.1"
chrono = "0.4.26"
reqwest = { version = "0.12.3" }
git-cliff-core = "2.7.0"
regex = "1.10.4"
chrono = "0.4.37"
lazy_static = "1.4.0"
parse-changelog = "0.6.1"
parse-changelog = "0.6.6"
toml_edit = "0.22.9"
tracing-test = "0.2"
pretty_assertions = "1.4"
[workspace.package]
version = "0.6.0"

1861
ci/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
[package]
name = "ci"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dagger-sdk = "*"
eyre = "*"
color-eyre = "*"
tokio = "1"
clap = {version = "4", features = ["derive"]}
futures = "0.3.28"
async-scoped = { version = "0.7.1", features = ["tokio", "use-tokio"] }
dotenv.workspace = true

View File

@@ -1,766 +0,0 @@
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use clap::Args;
use clap::Parser;
use clap::Subcommand;
use clap::ValueEnum;
use dagger_sdk::Platform;
use dagger_sdk::QueryContainerOpts;
use crate::please_release::run_release_please;
#[derive(Parser, Clone)]
#[command(author, version, about, long_about = None, subcommand_required = true)]
pub struct Command {
#[command(subcommand)]
commands: Commands,
#[command(flatten)]
global: GlobalArgs,
}
#[derive(Subcommand, Clone)]
pub enum Commands {
#[command(subcommand_required = true)]
Local {
#[command(subcommand)]
command: LocalCommands,
},
PullRequest {
#[arg(long)]
image: String,
#[arg(long)]
tag: String,
#[arg(long)]
bin_name: String,
},
Main {
#[arg(long)]
image: String,
#[arg(long)]
tag: String,
#[arg(long)]
bin_name: String,
},
Release,
}
#[derive(Subcommand, Clone)]
pub enum LocalCommands {
Build {
#[arg(long, default_value = "debug")]
profile: BuildProfile,
#[arg(long)]
bin_name: String,
},
Test,
DockerImage {
#[arg(long)]
image: String,
#[arg(long)]
tag: String,
#[arg(long)]
bin_name: String,
},
PleaseRelease,
BuildDocs {},
}
#[derive(Debug, Clone, ValueEnum)]
pub enum BuildProfile {
Debug,
Release,
}
#[derive(Debug, Clone, Args)]
pub struct GlobalArgs {
#[arg(long, global = true, help_heading = "Global")]
dry_run: bool,
#[arg(long, global = true, help_heading = "Global")]
rust_builder_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
production_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
mkdocs_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
caddy_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
source: Option<PathBuf>,
#[arg(long, global = true, help_heading = "Global")]
docs_image: Option<String>,
#[arg(long, global = true, help_heading = "Global")]
docs_image_tag: Option<String>,
}
#[tokio::main]
async fn main() -> eyre::Result<()> {
let _ = dotenv::dotenv();
let _ = color_eyre::install();
let client = dagger_sdk::connect().await?;
let cli = Command::parse();
match &cli.commands {
Commands::Local { command } => match command {
LocalCommands::Build {
profile: _,
bin_name,
} => {
let base_image = base_rust_image(
client.clone(),
&cli.global,
&None,
&bin_name.clone(),
&"release".into(),
)
.await?;
let prod_image = get_base_debian_image(client.clone(), &cli.global, None).await?;
build::execute(
client,
&cli.global,
&base_image,
&prod_image,
bin_name,
&None,
)
.await?;
}
LocalCommands::Test => {
let base_image = base_rust_image(
client.clone(),
&cli.global,
&None,
&"cuddle-please".into(),
&"debug".into(),
)
.await?;
test::execute(client, &cli.global, base_image).await?;
}
LocalCommands::DockerImage {
tag,
image,
bin_name,
} => {
build::build_and_deploy(client, &cli.global, bin_name, image, tag).await?;
}
LocalCommands::PleaseRelease => todo!(),
LocalCommands::BuildDocs {} => {
let _image = docs::execute(
client.clone(),
&cli.global,
&Some("linux/amd64".to_string()),
)
.await?;
}
},
Commands::PullRequest {
image,
tag,
bin_name,
} => {
async fn test(client: Arc<dagger_sdk::Query>, cli: &Command, bin_name: &String) {
let args = &cli.global;
let base_image =
base_rust_image(client.clone(), args, &None, bin_name, &"debug".into())
.await
.unwrap();
test::execute(client.clone(), args, base_image)
.await
.unwrap();
}
async fn build(
client: Arc<dagger_sdk::Query>,
cli: &Command,
bin_name: &String,
image: &String,
tag: &String,
) {
let args = &cli.global;
build::build(client.clone(), args, bin_name, image, tag)
.await
.unwrap();
}
tokio::join!(
test(client.clone(), &cli, bin_name),
build(client.clone(), &cli, bin_name, image, tag),
);
}
Commands::Main {
image,
tag,
bin_name,
} => {
async fn test(client: Arc<dagger_sdk::Query>, cli: &Command, bin_name: &String) {
let args = &cli.global;
let base_image =
base_rust_image(client.clone(), args, &None, bin_name, &"debug".into())
.await
.unwrap();
test::execute(client.clone(), args, base_image)
.await
.unwrap();
}
async fn build(
client: Arc<dagger_sdk::Query>,
cli: &Command,
bin_name: &String,
image: &String,
tag: &String,
) {
let args = &cli.global;
build::build_and_deploy(client.clone(), args, bin_name, image, tag)
.await
.unwrap();
}
async fn cuddle_please(client: Arc<dagger_sdk::Query>, cli: &Command) {
run_release_please(client.clone(), &cli.global)
.await
.unwrap();
}
tokio::join!(
test(client.clone(), &cli, bin_name),
build(client.clone(), &cli, bin_name, image, tag),
cuddle_please(client.clone(), &cli)
);
}
Commands::Release => todo!(),
}
Ok(())
}
mod please_release {
use std::sync::Arc;
use crate::{base_rust_image, GlobalArgs};
pub async fn run_release_please(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
) -> eyre::Result<()> {
let base_image = base_rust_image(
client.clone(),
args,
&Some("linux/amd64".to_string()),
&"cuddle-please".to_string(),
&"release".into(),
)
.await?;
let build_image = base_image.with_exec(vec![
"cargo",
"install",
"--target",
"x86_64-unknown-linux-gnu",
"--path=crates/cuddle-please",
]);
let src = client
.git_opts(
"https://git.front.kjuulh.io/kjuulh/cuddle-please",
dagger_sdk::QueryGitOpts {
experimental_service_host: None,
keep_git_dir: Some(true),
},
)
.branch("main")
.tree();
let res = build_image
.with_secret_variable(
"CUDDLE_PLEASE_TOKEN",
client
.set_secret("CUDDLE_PLEASE_TOKEN", std::env::var("CUDDLE_PLEASE_TOKEN")?)
.id()
.await?,
)
.with_workdir("/mnt/app")
.with_directory(".", src.id().await?)
.with_exec(vec![
"git",
"remote",
"set-url",
"origin",
&format!(
"https://git:{}@git.front.kjuulh.io/kjuulh/cuddle-please.git",
std::env::var("CUDDLE_PLEASE_TOKEN")?
),
])
.with_exec(vec![
"cuddle-please",
"release",
"--engine=gitea",
"--owner=kjuulh",
"--repo=cuddle-please",
"--branch=main",
"--api-url=https://git.front.kjuulh.io",
"--log-level=debug",
]);
let exit_code = res.exit_code().await?;
if exit_code != 0 {
eyre::bail!("failed to run cuddle-please");
}
let please_out = res.stdout().await?;
println!("{please_out}");
let please_out = res.stderr().await?;
println!("{please_out}");
Ok(())
}
}
mod docs {
use std::sync::Arc;
use dagger_sdk::Container;
use crate::GlobalArgs;
pub fn get_docs_src(client: Arc<dagger_sdk::Query>) -> eyre::Result<dagger_sdk::Directory> {
let docs_content = client.host().directory_opts(
".",
dagger_sdk::HostDirectoryOpts {
exclude: None,
include: Some(vec!["mkdocs.yml", "docs/"]),
},
);
Ok(docs_content)
}
pub async fn execute(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
_platform: &Option<String>,
) -> eyre::Result<Container> {
let mkdocs_container = client.container().from(
args.mkdocs_image
.as_ref()
.expect("--mkdocs-image to be set"),
);
let built_mkdocs_container = mkdocs_container
.with_directory("/docs", get_docs_src(client.clone())?.id().await?)
.with_exec(vec!["build"]);
let site_output = built_mkdocs_container.directory("/docs/site").id().await?;
let caddy_file = client.host().directory("templates").file("Caddyfile");
let dep_image = client
.container()
.from(args.caddy_image.as_ref().expect("--caddy-image to be set"))
.with_directory("/usr/share/caddy", site_output)
.with_file("/etc/caddy/Caddyfile", caddy_file.id().await?)
.with_exec(vec!["echo", "caddy"]);
Ok(dep_image)
}
pub async fn publish(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
containers: &Vec<dagger_sdk::Container>,
) -> eyre::Result<()> {
let container_ids =
futures::future::join_all(containers.iter().map(|c| c.id()).collect::<Vec<_>>()).await;
let container_ids = container_ids
.into_iter()
.collect::<eyre::Result<Vec<dagger_sdk::ContainerId>>>()?;
client
.container()
.publish_opts(
format!(
"{}:{}",
args.docs_image.as_ref().expect("--docs-image to be set"),
args.docs_image_tag
.as_ref()
.expect("--docs-image-tag to be set")
),
dagger_sdk::ContainerPublishOpts {
platform_variants: Some(container_ids),
},
)
.await?;
Ok(())
}
}
mod build {
use std::sync::Arc;
use dagger_sdk::Container;
use crate::{base_rust_image, get_base_debian_image, GlobalArgs};
pub async fn build_and_deploy(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
bin_name: &String,
image: &String,
tag: &String,
) -> eyre::Result<()> {
// let containers = vec!["linux/amd64", "linux/arm64"];
let base_image = get_base_debian_image(
client.clone(),
&args.clone(),
Some("linux/amd64".to_string()),
)
.await?;
let container = base_rust_image(
client.clone(),
args,
&Some("linux/amd64".to_string()),
&bin_name.clone(),
&"release".into(),
)
.await?;
let build_image = execute(
client.clone(),
args,
&container,
&base_image,
bin_name,
&Some("linux/amd64".to_string()),
)
.await?;
let build_id = build_image.id().await?;
let _container = client
.clone()
.container()
.publish_opts(
format!("{image}:{tag}"),
dagger_sdk::ContainerPublishOpts {
platform_variants: Some(vec![build_id]),
},
)
.await?;
Ok(())
}
pub async fn build(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
bin_name: &String,
_image: &String,
_tag: &String,
) -> eyre::Result<()> {
// let containers = vec!["linux/amd64", "linux/arm64"];
let base_image = get_base_debian_image(
client.clone(),
&args.clone(),
Some("linux/amd64".to_string()),
)
.await?;
let container = base_rust_image(
client.clone(),
args,
&Some("linux/amd64".to_string()),
&bin_name.clone(),
&"release".into(),
)
.await?;
let build_image = execute(
client.clone(),
args,
&container,
&base_image,
bin_name,
&Some("linux/amd64".to_string()),
)
.await?;
build_image.exit_code().await?;
Ok(())
}
pub async fn execute(
_client: Arc<dagger_sdk::Query>,
_args: &GlobalArgs,
container: &dagger_sdk::Container,
base_image: &dagger_sdk::Container,
bin_name: &String,
platform: &Option<String>,
) -> eyre::Result<Container> {
let rust_target = match platform
.clone()
.unwrap_or("linux/amd64".to_string())
.as_str()
{
"linux/amd64" => "x86_64-unknown-linux-gnu",
"linux/arm64" => "aarch64-unknown-linux-gnu",
_ => eyre::bail!("architecture not supported"),
};
let build_image = container.with_exec(vec![
"cargo",
"build",
"--target",
rust_target,
"--release",
"-p",
bin_name,
]);
let final_image = base_image
.with_file(
format!("/usr/local/bin/{}", &bin_name),
build_image
.file(format!("target/{}/release/{}", rust_target, &bin_name))
.id()
.await?,
)
.with_exec(vec![bin_name, "--help"]);
let output = final_image.stdout().await?;
println!("{output}");
//.with_entrypoint(vec![&bin_name, "--log-level=debug"]);
Ok(final_image)
}
}
mod test {
use std::sync::Arc;
use crate::GlobalArgs;
pub async fn execute(
_client: Arc<dagger_sdk::Query>,
_args: &GlobalArgs,
container: dagger_sdk::Container,
) -> eyre::Result<()> {
let test_image = container
.pipeline("rust:test")
.with_exec(vec!["apt", "update"])
.with_exec(vec!["apt", "install", "-y", "git"])
.with_exec(vec!["cargo", "test"]);
test_image.exit_code().await?;
Ok(())
}
}
pub async fn get_base_debian_image(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
platform: Option<String>,
) -> eyre::Result<dagger_sdk::Container> {
let default_platform = client.default_platform().await?;
let platform = platform.map(Platform).unwrap_or(default_platform);
let image = client
.container_opts(QueryContainerOpts {
id: None,
platform: Some(platform),
})
.from(
args.production_image
.clone()
.unwrap_or("debian:bullseye".to_string()),
);
let base_image = image.with_exec(vec!["apt", "update"]).with_exec(vec![
"apt",
"install",
"-y",
"libssl-dev",
"pkg-config",
"openssl",
"git",
"jq",
]);
Ok(base_image)
}
pub fn get_src(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
) -> eyre::Result<dagger_sdk::Directory> {
let directory = client.host().directory_opts(
args.source
.clone()
.unwrap_or(PathBuf::from("."))
.display()
.to_string(),
dagger_sdk::HostDirectoryOptsBuilder::default()
.exclude(vec!["node_modules/", ".git/", "target/"])
.build()?,
);
Ok(directory)
}
pub async fn get_rust_dep_src(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
) -> eyre::Result<dagger_sdk::Directory> {
let directory = client.host().directory_opts(
args.source
.clone()
.unwrap_or(PathBuf::from("."))
.display()
.to_string(),
dagger_sdk::HostDirectoryOptsBuilder::default()
.include(vec!["**/Cargo.toml", "**/Cargo.lock"])
.build()?,
);
Ok(directory)
}
pub async fn get_rust_skeleton_files(
client: Arc<dagger_sdk::Query>,
_args: &GlobalArgs,
) -> eyre::Result<(dagger_sdk::Directory, Vec<String>)> {
let mut rust_crates = vec![PathBuf::from("ci")];
let mut dirs = tokio::fs::read_dir("crates").await?;
while let Some(entry) = dirs.next_entry().await? {
if entry.metadata().await?.is_dir() {
rust_crates.push(entry.path())
}
}
fn create_skeleton_files(
directory: dagger_sdk::Directory,
path: &Path,
) -> eyre::Result<dagger_sdk::Directory> {
println!("found crates: {}", path.display());
let main_content = r#"
#[allow(dead_code)]
fn main() { panic!("should never be executed"); }"#;
let lib_content = r#"
#[allow(dead_code)]
fn some() { panic!("should never be executed"); }"#;
let directory = directory.with_new_file(
path.join("src").join("main.rs").display().to_string(),
main_content,
);
let directory = directory.with_new_file(
path.join("src").join("lib.rs").display().to_string(),
lib_content,
);
Ok(directory)
}
let mut directory = client.directory();
let mut crate_names = Vec::new();
for rust_crate in rust_crates.iter() {
if let Some(file_name) = rust_crate.file_name() {
crate_names.push(file_name.to_str().unwrap().to_string());
}
directory = create_skeleton_files(directory, rust_crate)?;
}
Ok((directory, crate_names))
}
pub async fn base_rust_image(
client: Arc<dagger_sdk::Query>,
args: &GlobalArgs,
platform: &Option<String>,
bin_name: &String,
profile: &String,
) -> eyre::Result<dagger_sdk::Container> {
let dep_src = get_rust_dep_src(client.clone(), args).await?;
let (skeleton_files, crates) = get_rust_skeleton_files(client.clone(), args).await?;
let src = get_src(client.clone(), args)?;
let client = client.pipeline("rust_base_image");
let rust_target = match platform
.clone()
.unwrap_or("linux/amd64".to_string())
.as_str()
{
"linux/amd64" => "x86_64-unknown-linux-gnu",
"linux/arm64" => "aarch64-unknown-linux-gnu",
_ => eyre::bail!("architecture not supported"),
};
let rust_build_image = client
.container()
.from(
args.rust_builder_image
.as_ref()
.unwrap_or(&"rustlang/rust:nightly".into()),
)
.with_exec(vec!["rustup", "target", "add", rust_target])
.with_exec(vec!["apt", "update"])
.with_exec(vec!["apt", "install", "-y", "jq"]);
let target_cache = client.cache_volume(format!("rust_target_{}", profile));
let mut build_options = vec!["cargo", "build", "--target", rust_target, "-p", bin_name];
if profile == "release" {
build_options.push("--release");
}
let rust_prebuild = rust_build_image
.with_workdir("/mnt/src")
.with_directory("/mnt/src", dep_src.id().await?)
.with_directory("/mnt/src/", skeleton_files.id().await?)
.with_exec(build_options)
.with_mounted_cache("/mnt/src/target/", target_cache.id().await?);
let exclude = crates
.iter()
.filter(|c| **c != "ci")
.map(|c| format!("**/*{}*", c.replace('-', "_")))
.collect::<Vec<_>>();
let exclude = exclude.iter().map(|c| c.as_str()).collect();
let incremental_dir = client.directory().with_directory_opts(
".",
rust_prebuild.directory("target").id().await?,
dagger_sdk::DirectoryWithDirectoryOpts {
exclude: Some(exclude),
include: None,
},
);
let rust_with_src = rust_build_image
.with_workdir("/mnt/src")
.with_directory(
"/usr/local/cargo",
rust_prebuild.directory("/usr/local/cargo").id().await?,
)
.with_directory("target", incremental_dir.id().await?)
.with_directory("/mnt/src/", src.id().await?);
Ok(rust_with_src)
}

View File

@@ -0,0 +1,19 @@
[package]
name = "cuddle-please-actions"
description = "A release-please inspired release manager tool, built on top of cuddle, but also useful standalone, cuddle-please supports, your ci of choice, as well as gitea, github"
repository = "https://git.front.kjuulh.io/kjuulh/cuddle-please"
readme = "../../README.md"
license-file = "../../LICENSE"
version = "0.1.0"
edition = "2021"
publish = true
[dependencies]
anyhow.workspace = true
tracing.workspace = true
semver.workspace = true
toml_edit.workspace = true
yaml-rust2.workspace = true
[dev-dependencies]
pretty_assertions.workspace = true

View File

@@ -0,0 +1,9 @@
use semver::Version;
use crate::ActionConfig;
pub trait Action {
fn enabled(&self, config: &ActionConfig) -> anyhow::Result<bool>;
fn name(&self) -> String;
fn execute(&self, version: &Version) -> anyhow::Result<()>;
}

View File

@@ -0,0 +1,49 @@
use std::ops::Deref;
use anyhow::Context;
pub enum ActionConfig {
Actual { doc: yaml_rust2::Yaml },
None,
}
impl Deref for ActionConfig {
type Target = yaml_rust2::Yaml;
fn deref(&self) -> &Self::Target {
match &self {
ActionConfig::Actual { doc } => doc,
ActionConfig::None => &yaml_rust2::Yaml::BadValue,
}
}
}
impl TryFrom<&str> for ActionConfig {
type Error = anyhow::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut cuddle = yaml_rust2::YamlLoader::load_from_str(value)?;
if cuddle.len() != 1 {
anyhow::bail!("cuddle.yaml can only be 1 document wide");
}
let doc = cuddle.pop().unwrap();
let doc = doc["please"]["actions"].clone();
if doc.is_badvalue() {
return Ok(Self::None);
}
Ok(Self::Actual { doc })
}
}
impl ActionConfig {
pub fn parse() -> anyhow::Result<Self> {
let cuddle_yaml =
std::fs::read_to_string("cuddle.yaml").context("failed to read cuddle.yaml")?;
Self::try_from(cuddle_yaml.as_str())
}
}

View File

@@ -0,0 +1,45 @@
pub(crate) mod actions;
mod config;
mod rust_action;
use std::{ops::Deref, sync::Arc};
use catalog::RustAction;
pub use config::ActionConfig;
use semver::Version;
pub mod catalog {
pub use crate::rust_action::*;
}
pub struct Action(Arc<dyn actions::Action>);
impl Deref for Action {
type Target = Arc<dyn actions::Action>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct Actions(Vec<Action>);
impl Actions {
pub fn from_cuddle() -> anyhow::Result<Self> {
let config = ActionConfig::parse()?;
Ok(Self(
vec![Action(Arc::new(RustAction::new()))]
.into_iter()
.filter(|a| a.enabled(&config).unwrap_or_default())
.collect(),
))
}
pub fn execute(&self, version: &Version) -> anyhow::Result<()> {
for action in &self.0 {
action.execute(version)?;
}
Ok(())
}
}

View File

@@ -0,0 +1,235 @@
use std::io::Write;
use crate::{actions::Action, ActionConfig};
#[derive(Default, Clone)]
pub struct RustAction {}
impl RustAction {
pub fn new() -> Self {
Self {}
}
fn execute_content(
&self,
version: &semver::Version,
cargo_content: &str,
) -> anyhow::Result<String> {
tracing::trace!("parsing Cargo.toml file as tolm");
let mut cargo_doc = cargo_content.parse::<toml_edit::DocumentMut>()?;
tracing::debug!(
"updating cargo workspace package version to {}",
version.to_string()
);
let workspace = if cargo_doc.contains_table("workspace") {
cargo_doc["workspace"].as_table_mut().unwrap()
} else {
let mut t = toml_edit::Table::new();
t.set_implicit(true);
cargo_doc["workspace"] = toml_edit::Item::Table(t);
cargo_doc["workspace"].as_table_mut().unwrap()
};
let package = workspace["package"].or_insert(toml_edit::table());
package["version"] = toml_edit::value(version.to_string());
Ok(cargo_doc.to_string())
}
}
impl Action for RustAction {
fn enabled(&self, config: &ActionConfig) -> anyhow::Result<bool> {
if let Ok(v) = std::env::var("CUDDLE_PLEASE_RUST_ACTION") {
if let Ok(true) = v.parse::<bool>() {
return Ok(true);
}
}
let val = &config[self.name().as_str()];
if val.is_badvalue() {
return Ok(false);
}
Ok(val.as_bool().unwrap_or(true))
}
fn name(&self) -> String {
"rust".into()
}
fn execute(&self, version: &semver::Version) -> anyhow::Result<()> {
tracing::info!(
"running rust action for version: {} and file: Cargo.toml",
version.to_string()
);
let path = std::path::PathBuf::from("Cargo.toml");
tracing::trace!("reading Cargo.toml");
let file = match std::fs::read_to_string(&path) {
Ok(file) => file,
Err(e) => match e.kind() {
std::io::ErrorKind::NotFound => {
anyhow::bail!("err: Cargo.toml was not found in dir")
}
_ => Err(e)?,
},
};
let cargo_doc = self.execute_content(version, &file)?;
let mut cargo_file = std::fs::File::create(&path)?;
cargo_file.write_all(cargo_doc.as_bytes())?;
cargo_file.sync_all()?;
tracing::debug!("finished writing cargo file");
Ok(())
}
}
#[cfg(test)]
mod test {
use semver::{BuildMetadata, Prerelease};
use crate::{actions::Action, ActionConfig};
use super::RustAction;
#[test]
fn test_is_enabled() {
let config = ActionConfig::try_from(
r#"
please:
actions:
rust: true
"#,
)
.unwrap();
let enabled = RustAction::new().enabled(&config).unwrap();
assert!(enabled)
}
#[test]
fn test_is_disabled_by_default() {
let config = ActionConfig::try_from(
r#"
please:
"#,
)
.unwrap();
let enabled = RustAction::new().enabled(&config).unwrap();
assert!(!enabled)
}
#[test]
fn test_is_disabled() {
let config = ActionConfig::try_from(
r#"
please:
actions:
rust: false
"#,
)
.unwrap();
let enabled = RustAction::new().enabled(&config).unwrap();
assert!(!enabled)
}
#[test]
fn test_missing_value_is_enabled() {
let config = ActionConfig::try_from(
r#"
please:
actions:
rust:
"#,
)
.unwrap();
let enabled = RustAction::new().enabled(&config).unwrap();
assert!(enabled)
}
#[test]
fn test_can_edit_empty_file() {
let output = RustAction::default()
.execute_content(
&semver::Version {
major: 0,
minor: 1,
patch: 0,
pre: Prerelease::default(),
build: BuildMetadata::default(),
},
"",
)
.unwrap();
pretty_assertions::assert_eq!(
r#"[workspace.package]
version = "0.1.0"
"#,
&output,
)
}
#[test]
fn test_only_edits_stuff() {
let input = r#"
[workspace]
members = ["."]
[package]
something = {some = "something"}
# Some comment
[workspace.package]
version = "0.0.0" # some comment
readme = "../../"
"#;
let output = RustAction::default()
.execute_content(
&semver::Version {
major: 0,
minor: 1,
patch: 0,
pre: Prerelease::default(),
build: BuildMetadata::default(),
},
input,
)
.unwrap();
pretty_assertions::assert_eq!(
r#"
[workspace]
members = ["."]
[package]
something = {some = "something"}
# Some comment
[workspace.package]
version = "0.1.0"
readme = "../../"
"#,
&output,
)
}
}

View File

@@ -6,18 +6,19 @@ readme = "../../README.md"
license-file = "../../LICENSE"
version = "0.1.0"
edition = "2021"
publishable = true
publish = true
[dependencies]
cuddle-please-frontend.workspace = true
cuddle-please-misc.workspace = true
cuddle-please-actions.workspace = true
anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
dotenv.workspace = true
dotenvy.workspace = true
serde_yaml.workspace = true
serde.workspace = true
reqwest = { workspace = true, features = ["blocking", "json"] }

View File

@@ -6,6 +6,7 @@ use std::{
};
use clap::{Parser, Subcommand};
use cuddle_please_actions::Actions;
use cuddle_please_frontend::{gatheres::ConfigArgs, PleaseConfig, PleaseConfigBuilder};
use cuddle_please_misc::{
ConsoleUi, DynRemoteGitClient, DynUi, GiteaClient, GlobalArgs, LocalGitClient, StdinFn,
@@ -90,26 +91,27 @@ impl Command {
}
pub fn execute(self, current_dir: Option<&Path>) -> anyhow::Result<()> {
match &self.commands {
Some(Commands::Release {}) => {
let (config, git_client, gitea_client) = self.get_deps(current_dir)?;
ReleaseCommandHandler::new(self.ui, config, git_client, gitea_client)
.execute(self.global.dry_run)?;
}
Some(Commands::Config { command }) => {
let (config, _, _) = self.get_deps(current_dir)?;
ConfigCommandHandler::new(self.ui, config).execute(command)?;
}
Some(Commands::Gitea { command }) => {
let (config, _, gitea_client) = self.get_deps(current_dir)?;
if let Some(c) = &self.commands {
match c {
Commands::Release {} => {
let (config, git_client, gitea_client, actions) = self.get_deps(current_dir)?;
ReleaseCommandHandler::new(self.ui, config, git_client, gitea_client, actions)
.execute(self.global.dry_run)?;
}
Commands::Config { command } => {
let (config, _, _, _) = self.get_deps(current_dir)?;
ConfigCommandHandler::new(self.ui, config).execute(command)?;
}
Commands::Gitea { command } => {
let (config, _, gitea_client, _) = self.get_deps(current_dir)?;
GiteaCommandHandler::new(self.ui, config, gitea_client)
.execute(command, self.global.token.expect("token to be set").deref())?;
GiteaCommandHandler::new(self.ui, config, gitea_client)
.execute(command, self.global.token.expect("token to be set").deref())?;
}
Commands::Doctor {} => {
DoctorCommandHandler::new(self.ui).execute()?;
}
}
Some(Commands::Doctor {}) => {
DoctorCommandHandler::new(self.ui).execute()?;
}
None => {}
}
Ok(())
@@ -118,7 +120,7 @@ impl Command {
fn get_deps(
&self,
current_dir: Option<&Path>,
) -> anyhow::Result<(PleaseConfig, VcsClient, DynRemoteGitClient)> {
) -> anyhow::Result<(PleaseConfig, VcsClient, DynRemoteGitClient, Actions)> {
let config = self.build_config(current_dir)?;
let git_client =
self.get_git(&config, self.global.token.clone().expect("token to be set"))?;
@@ -140,7 +142,9 @@ impl Command {
tracing_subscriber::fmt().with_env_filter(env_filter).init();
}
Ok((config, git_client, gitea_client))
let actions = self.get_actions()?;
Ok((config, git_client, gitea_client, actions))
}
fn build_config(&self, current_dir: Option<&Path>) -> Result<PleaseConfig, anyhow::Error> {
@@ -183,6 +187,10 @@ impl Command {
)),
}
}
fn get_actions(&self) -> anyhow::Result<Actions> {
Actions::from_cuddle()
}
}
#[derive(Debug, Clone, Subcommand)]

View File

@@ -1,3 +1,6 @@
use std::path::Path;
use cuddle_please_actions::Actions;
use cuddle_please_frontend::PleaseConfig;
use ::semver::Version;
@@ -13,6 +16,7 @@ pub struct ReleaseCommandHandler {
config: PleaseConfig,
git_client: VcsClient,
gitea_client: DynRemoteGitClient,
actions: Actions,
}
impl ReleaseCommandHandler {
@@ -21,12 +25,14 @@ impl ReleaseCommandHandler {
config: PleaseConfig,
git_client: VcsClient,
gitea_client: DynRemoteGitClient,
actions: Actions,
) -> Self {
Self {
ui,
config,
git_client,
gitea_client,
actions,
}
}
@@ -69,6 +75,8 @@ impl ReleaseCommandHandler {
let (changelog_placement, changelog, changelog_last_changes) =
compose_changelog(&commit_strs, &next_version, source)?;
self.actions.execute(&next_version)?;
if let Some(first_commit) = commit_strs.first() {
if first_commit.contains("chore(release): ") {
tracing::trace!("creating release");
@@ -122,6 +130,7 @@ impl ReleaseCommandHandler {
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn create_pull_request(
&self,
changelog_placement: std::path::PathBuf,
@@ -219,7 +228,7 @@ impl ReleaseCommandHandler {
fn compose_changelog(
commit_strs: &Vec<String>,
next_version: &Version,
source: &std::path::PathBuf,
source: &Path,
) -> Result<(std::path::PathBuf, String, Option<String>), anyhow::Error> {
let builder = ChangeLogBuilder::new(commit_strs, next_version.to_string()).build();
let changelog_placement = source.join("CHANGELOG.md");

View File

@@ -6,14 +6,14 @@ readme = "../../README.md"
license-file = "../../LICENSE"
version = "0.1.0"
edition = "2021"
publishable = true
publish = true
[dependencies]
anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
dotenv.workspace = true
dotenvy.workspace = true
serde_yaml.workspace = true
serde.workspace = true
chrono.workspace = true

View File

@@ -28,14 +28,8 @@ pub struct PleaseConfigBuilder {
impl PleaseConfigBuilder {
pub fn merge(&mut self, config: &PleaseConfigBuilder) -> &Self {
let config = config.clone();
let mut fproject = match self.project.clone() {
None => PleaseProjectConfigBuilder::default(),
Some(project) => project,
};
let mut fsettings = match self.settings.clone() {
None => PleaseSettingsConfigBuilder::default(),
Some(settings) => settings,
};
let mut fproject = self.project.clone().unwrap_or_default();
let mut fsettings = self.settings.clone().unwrap_or_default();
if let Some(project) = config.project {
if let Some(owner) = project.owner {

View File

@@ -6,7 +6,7 @@ readme = "../../README.md"
license-file = "../../LICENSE"
version = "0.1.0"
edition = "2021"
publishable = true
publish = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -15,7 +15,7 @@ anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
dotenv.workspace = true
dotenvy.workspace = true
serde_yaml.workspace = true
serde.workspace = true
reqwest = { workspace = true, features = ["blocking", "json"] }
@@ -29,6 +29,9 @@ chrono.workspace = true
lazy_static.workspace = true
parse-changelog.workspace = true
# Cliff depends on 13.1.0, which is a broken release
cacache = "=13.0.0"
[dev-dependencies]
tracing-test = { workspace = true, features = ["no-env-filter"] }
pretty_assertions.workspace = true

View File

@@ -3,7 +3,7 @@ use chrono::{DateTime, NaiveDate, Utc};
use git_cliff_core::{
changelog::Changelog,
commit::Commit,
config::{ChangelogConfig, CommitParser, Config, GitConfig},
config::{Bump, ChangelogConfig, CommitParser, Config, GitConfig, RemoteConfig},
release::Release,
};
use regex::Regex;
@@ -77,6 +77,9 @@ impl ChangeLogBuilder {
commit_id: None,
timestamp,
previous: None,
message: None,
repository: None,
extra: None,
},
config: self.config,
release_link: self.release_link,
@@ -86,7 +89,7 @@ impl ChangeLogBuilder {
fn release_timestamp(&self) -> i64 {
self.release_date
.and_then(|date| date.and_hms_opt(0, 0, 0))
.map(|d| DateTime::<Utc>::from_utc(d, Utc))
.map(|d| DateTime::<Utc>::from_naive_utc_and_offset(d, Utc))
.unwrap_or_else(Utc::now)
.timestamp()
}
@@ -139,6 +142,8 @@ impl ChangeLog<'_> {
let config = Config {
changelog: default_changelog_config(None, self.release_link.as_deref()),
git: default_git_config(),
remote: RemoteConfig::default(),
bump: Bump::default(),
};
config
@@ -148,6 +153,8 @@ impl ChangeLog<'_> {
let config = Config {
changelog: default_changelog_config(header, self.release_link.as_deref()),
git: default_git_config(),
remote: RemoteConfig::default(),
bump: Bump::default(),
};
config
@@ -173,6 +180,10 @@ fn default_commit_parsers() -> Vec<CommitParser> {
default_scope: None,
scope: None,
skip: None,
field: None,
pattern: None,
sha: None,
footer: None,
}
}
@@ -191,6 +202,10 @@ fn default_commit_parsers() -> Vec<CommitParser> {
default_scope: None,
skip: None,
scope: None,
field: None,
pattern: None,
sha: None,
footer: None,
},
]
}
@@ -210,6 +225,9 @@ fn default_changelog_config(header: Option<String>, release_link: Option<&str>)
body: Some(default_changelog_body_config(release_link)),
footer: None,
trim: Some(true),
postprocessors: None,
render_always: None,
output: None,
}
}
@@ -225,6 +243,11 @@ fn default_changelog_body_config(release_link: Option<&str>) -> String {
{% else -%}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}
{% endif -%}
{%- if commit.body -%}
{%- if commit.body | length > 0 -%}
{% raw %} {% endraw %}{{ commit.body | trim }}
{% endif -%}
{% endif -%}
{% endfor -%}
{% endfor %}"#;
@@ -497,7 +520,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#[test]
fn generates_changelog() {
let commits: Vec<&str> = vec![
"feat: some feature",
"feat: some feature
some body",
"some random commit",
"fix: some fix",
"chore(scope): some chore",
@@ -518,6 +543,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- some feature
some body
### Fixed
- some fix

View File

@@ -79,6 +79,13 @@ impl VcsClient {
let stdout = std::str::from_utf8(&checkout_branch.stdout)?;
let stderr = std::str::from_utf8(&checkout_branch.stderr)?;
tracing::debug!(stdout = stdout, stderr = stderr, "git {}", args.join(" "));
let exit_code = checkout_branch.status;
if !exit_code.success() {
anyhow::bail!(
"failed to run git command: {}",
exit_code.code().unwrap_or(-1)
)
}
}
}

View File

@@ -517,6 +517,7 @@ impl TryFrom<Tag> for Version {
tracing::trace!(name = &value.name, "parsing tag into version");
value
.name
.trim_start_matches("v")
.parse::<Version>()
.context("could not get version from tag")
}
@@ -601,7 +602,7 @@ mod test {
let (expected, actual) = get_commits("second-sha".into()).unwrap();
assert_eq!(
expected.get(0).unwrap().clone().as_slice(),
expected.first().unwrap().clone().as_slice(),
actual.as_slice()
);
}

View File

@@ -1,5 +1,6 @@
use crate::RemoteGitEngine;
#[derive(Default)]
pub struct LocalGitClient {}
impl LocalGitClient {

View File

@@ -6,20 +6,18 @@ version = "0.1.0"
edition = "2021"
readme = "../../README.md"
license-file = "../../LICENSE"
publishable = true
publish = true
[dependencies]
anyhow.workspace = true
tracing.workspace = true
serde.workspace = true
semver.workspace = true
cargo_metadata = "0.17.0"
[dev-dependencies]
tracing-test = { workspace = true, features = ["no-env-filter"] }
pretty_assertions.workspace = true
tempdir.workspace = true
serde_json.workspace = true
[features]
rust-workspace = []
@@ -29,6 +27,5 @@ json-edit = []
yaml-edit = []
default = [
"json-edit",
"rust-workspace"
"json-edit"
]

View File

@@ -1,11 +1,6 @@
#[cfg(feature = "json-edit")]
mod json_edit;
#[cfg(feature = "rust-workspace")]
mod rust_workspace;
mod strategy;
#[cfg(feature = "json-edit")]
pub use json_edit::JsonEditOptions;
#[cfg(feature = "rust-workspace")]
pub use rust_workspace::RustWorkspaceOptions;

View File

@@ -1,72 +0,0 @@
use std::path::{Path, PathBuf};
use anyhow::Context;
use cargo_metadata::camino::{Utf8Path, Utf8PathBuf};
use serde::{Deserialize, Serialize};
fn lock_step_default() -> bool {
true
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RustWorkspaceOptions {
#[serde(default = "lock_step_default")]
pub lock_step: bool,
}
impl RustWorkspaceOptions {
pub fn execute(&self, path: &Path, next_version: impl AsRef<str>) -> anyhow::Result<()> {
let members = self.get_workspace(path)?;
Ok(())
}
pub fn get_workspace(&self, path: &Path) -> anyhow::Result<Vec<cargo_metadata::Package>> {
let entries = std::fs::read_dir(path)
.context(anyhow::anyhow!("could not read dir: {}", path.display()))?
.flatten()
.filter(|p| p.file_name().to_str().unwrap() == "Cargo.toml")
.collect::<Vec<_>>();
let cargo_manifest_file = match entries.first() {
Some(x) => x,
None => anyhow::bail!("did not find any Cargo.toml in: {}", path.display()),
};
let mut cmd = cargo_metadata::MetadataCommand::new();
let manifest = cmd
.no_deps()
.manifest_path(cargo_manifest_file.path())
.exec()
.context("could not parse manifest")?;
let members = manifest.workspace_members.iter().collect::<Vec<_>>();
let workspace_members = manifest
.packages
.into_iter()
.filter(|p| members.contains(&&p.id))
.map(|mut p| {
p.manifest_path = abs_path(&p.manifest_path);
for dependency in p.dependencies.iter_mut() {
dependency.path = dependency.path.take().map(|path| abs_path(&path))
}
p
})
.collect::<Vec<_>>();
Ok(workspace_members)
}
}
fn abs_path(path: &Utf8Path) -> Utf8PathBuf {
match path.canonicalize_utf8() {
Ok(path) => path,
Err(e) => {
tracing::debug!("failed to transform manifest_path into abs path: {}", path);
path.to_path_buf()
}
}
}

View File

@@ -2,11 +2,13 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[allow(dead_code)]
pub struct UpdateOptions {
next_version: String,
global_changelog: String,
}
#[allow(dead_code)]
pub type Projects = Vec<Project>;
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -22,7 +24,7 @@ pub enum ProjectType {
#[serde(alias = "rust_workspace")]
RustWorkspace,
#[cfg(feature = "rust-crate")]
#[serde(alias = "json_edit")]
#[serde(alias = "rust_crate")]
RustCrate,
#[cfg(feature = "toml-edit")]
#[serde(alias = "toml_edit")]
@@ -35,12 +37,13 @@ pub enum ProjectType {
JsonEdit,
}
#[allow(dead_code)]
impl Project {
pub fn new(path: Option<PathBuf>, r#type: ProjectType) -> Self {
Self { path, r#type }
}
pub fn execute(&self, options: &UpdateOptions) -> anyhow::Result<()> {
pub fn execute(&self, _options: &UpdateOptions) -> anyhow::Result<()> {
match self.r#type {
#[cfg(feature = "rust-workspace")]
ProjectType::RustWorkspace => todo!(),
@@ -53,7 +56,5 @@ impl Project {
#[cfg(feature = "json-edit")]
ProjectType::JsonEdit => todo!(),
}
Ok(())
}
}

View File

@@ -1,60 +0,0 @@
use cargo_metadata::{
camino::{Utf8Path, Utf8PathBuf},
Package,
};
use cuddle_please_release_strategy::RustWorkspaceOptions;
use serde_json::json;
use tracing_test::traced_test;
#[test]
#[traced_test]
fn test_can_read_manifest() {
let temp = tempdir::TempDir::new("test_rust_workspace_can_read_manifest").unwrap();
let temp_path = temp.path();
std::fs::write(
temp_path.join("Cargo.toml"),
r#"
[workspace]
members = [
"nested"
]
[workspace.dependencies]
nested = { path = "nested" }
"#,
)
.unwrap();
std::fs::create_dir_all(temp_path.join("nested")).unwrap();
std::fs::write(
temp_path.join("nested").join("Cargo.toml"),
r#"
[package]
name = "nested"
version = "0.1.0"
edition = "2021"
[dependencies]
nested.workspace = true
"#,
)
.unwrap();
std::fs::create_dir_all(temp_path.join("nested").join("src")).unwrap();
std::fs::write(
temp_path.join("nested").join("src").join("lib.rs"),
r#"
#[test]
test () {}
"#,
)
.unwrap();
let options = RustWorkspaceOptions { lock_step: true };
let members = options.get_workspace(temp_path).unwrap();
assert!(!members.is_empty());
let first = members.first().unwrap();
pretty_assertions::assert_eq!("nested", &first.name);
}

View File

@@ -6,7 +6,7 @@ readme = "../../README.md"
license-file = "../../LICENSE"
version = "0.1.0"
edition = "2021"
publishable = true
publish = true
[dependencies]
cuddle-please-frontend.workspace = true
@@ -17,7 +17,7 @@ anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
dotenv.workspace = true
dotenvy.workspace = true
serde_yaml.workspace = true
serde.workspace = true
reqwest = { workspace = true, features = ["blocking", "json"] }

View File

@@ -1,14 +1,12 @@
use cuddle_please_commands::PleaseCommand;
fn main() -> anyhow::Result<()> {
dotenv::dotenv().ok();
dotenvy::dotenv().ok();
let current_dir = std::env::current_dir().ok();
let current_dir = current_dir.as_deref();
PleaseCommand::new().execute(current_dir)?;
//something else asdfa 123
Ok(())
}

View File

@@ -6,6 +6,7 @@ use tracing_test::traced_test;
use crate::common::{assert_output, get_test_data_path};
#[allow(dead_code)]
fn get_base_args<'a>() -> Vec<&'a str> {
vec![
"cuddle-please",
@@ -25,7 +26,7 @@ PleaseConfig
api_url: https://some-example.gitea-instance
"#;
#[test]
#[allow(dead_code)]
#[traced_test]
fn test_config_from_current_dir() {
let args = get_base_args();
@@ -39,7 +40,7 @@ fn test_config_from_current_dir() {
assert_output(ui, EXPECTED_OUTPUT, "");
}
#[test]
#[allow(dead_code)]
#[traced_test]
fn test_config_from_source_dir() {
let mut args = get_base_args();
@@ -55,7 +56,7 @@ fn test_config_from_source_dir() {
assert_output(ui, EXPECTED_OUTPUT, "");
}
#[test]
#[allow(dead_code)]
#[traced_test]
fn test_config_from_stdin() {
let mut args = get_base_args();
@@ -75,7 +76,7 @@ settings:
assert_output(ui, EXPECTED_OUTPUT, "");
}
#[test]
#[allow(dead_code)]
#[traced_test]
fn test_config_fails_when_not_path_is_set() {
let args = get_base_args();

View File

@@ -16,15 +16,18 @@ fn test_vcs_get_noop() {
#[traced_test]
fn test_vcs_get_git_found() {
let testdata = get_test_data_path("git-found");
if let Err(e) = std::fs::create_dir_all(&testdata) {
tracing::error!("failed to create dir: {}", e);
}
if let Err(e) = std::process::Command::new("git")
.arg("init")
.arg(".")
.current_dir(&testdata)
.output()
{
println!("{e}");
println!("testdata git dir not found: {e}");
}
return;
let git = VcsClient::new_git(&testdata, None::<String>, None::<String>, "".into()).unwrap();
assert_eq!(
git,

View File

@@ -16,6 +16,18 @@ please:
branch: main
settings:
api_url: https://git.front.kjuulh.io
actions:
rust:
components:
packages:
debian:
dev:
- jq
- git
release:
- jq
- git
scripts:
"mkdocs:new":
@@ -34,4 +46,4 @@ scripts:
type: shell
"ci:release":
type: shell

View File

@@ -12,6 +12,4 @@ fi
$CMD_PREFIX pull-request \
--mkdocs-image "$MKDOCS_IMAGE" \
--caddy-image "$CADDY_IMAGE" \
--image "$REGISTRY/$SERVICE" \
--tag "main-$(date +%s)" \
--bin-name "$SERVICE"

17
scripts/ci:release.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -e
CMD_PREFIX="cargo run -p ci --"
if [[ -n "$CI_PREFIX" ]]; then
CMD_PREFIX="$CI_PREFIX"
fi
$CMD_PREFIX release \
--mkdocs-image "$MKDOCS_IMAGE" \
--caddy-image "$CADDY_IMAGE" \
--image "$REGISTRY/$SERVICE" \
--tag "$DRONE_TAG" \
--bin-name "$SERVICE"