Skip to content

Commit 04c1753

Browse files
committed
refactor: refactor to solve sonarcloud issues
1 parent c359f4b commit 04c1753

File tree

4 files changed

+148
-95
lines changed

4 files changed

+148
-95
lines changed

.dev/00-README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Development documentation for zerv - Dynamic Versioning CLI
2727

2828
```bash
2929
# Fast development cycle (no Docker required)
30-
make test_fast # Run unit tests only
3130
make lint # Format and check code
3231
make run # Test CLI binary
3332

.dev/00-archived-insights.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848

4949
- Fast local tests without external dependencies
5050
- Docker-based integration tests for real VCS operations
51-
- Separate test commands (`make test_fast` vs `make test`)
5251

5352
**Status**: ✅ Successfully implemented and working
5453

.github/workflows/trivy.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: security
2+
on:
3+
pull_request:
4+
push:
5+
workflow_dispatch:
6+
schedule:
7+
- cron: "0 4 * * *" # run once a day at 4 AM
8+
9+
jobs:
10+
trivy-scan:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v3
16+
17+
- name: Run Trivy dependency scan
18+
uses: aquasecurity/trivy-action@v1
19+
with:
20+
scan-type: fs
21+
format: table
22+
exit-code: "1"
23+
vuln-type: "os,library"
24+
25+
gitleaks:
26+
name: gitleaks
27+
runs-on: ubuntu-latest
28+
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 0
33+
34+
- uses: gitleaks/gitleaks-action@v2
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

src/version/semver/to_zerv.rs

Lines changed: 112 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,113 @@ use crate::version::zerv::{
33
Component, PreReleaseVar, Zerv, ZervSchema, ZervVars, normalize_pre_release_label,
44
};
55

6+
type ProcessResult = (
7+
Option<PreReleaseVar>,
8+
Vec<Component>,
9+
Option<u64>,
10+
Option<u64>,
11+
Option<u64>,
12+
);
13+
14+
struct PreReleaseProcessor {
15+
pre_release: Option<PreReleaseVar>,
16+
extra_core: Vec<Component>,
17+
epoch: Option<u64>,
18+
post: Option<u64>,
19+
dev: Option<u64>,
20+
}
21+
22+
impl PreReleaseProcessor {
23+
fn new() -> Self {
24+
Self {
25+
pre_release: None,
26+
extra_core: Vec::new(),
27+
epoch: None,
28+
post: None,
29+
dev: None,
30+
}
31+
}
32+
33+
fn try_special_pattern(&mut self, pr: &[PreReleaseIdentifier], i: usize) -> bool {
34+
if i + 1 >= pr.len() {
35+
return false;
36+
}
37+
38+
if let (PreReleaseIdentifier::String(label), PreReleaseIdentifier::Integer(num)) =
39+
(&pr[i], &pr[i + 1])
40+
{
41+
match label.as_str() {
42+
"epoch" if self.epoch.is_none() => {
43+
self.epoch = Some(*num);
44+
self.extra_core
45+
.push(Component::VarField("epoch".to_string()));
46+
true
47+
}
48+
"dev" if self.dev.is_none() => {
49+
self.dev = Some(*num);
50+
self.extra_core.push(Component::VarField("dev".to_string()));
51+
true
52+
}
53+
"post" if self.post.is_none() => {
54+
self.post = Some(*num);
55+
self.extra_core
56+
.push(Component::VarField("post".to_string()));
57+
true
58+
}
59+
_ => self.try_pre_release_pattern(label, Some(*num)),
60+
}
61+
} else {
62+
false
63+
}
64+
}
65+
66+
fn try_pre_release_pattern(&mut self, label: &str, number: Option<u64>) -> bool {
67+
if let Some(normalized_label) = normalize_pre_release_label(label)
68+
&& self.pre_release.is_none()
69+
{
70+
self.pre_release = Some(PreReleaseVar {
71+
label: normalized_label,
72+
number,
73+
});
74+
self.extra_core
75+
.push(Component::VarField("pre_release".to_string()));
76+
return true;
77+
}
78+
false
79+
}
80+
81+
fn add_regular_component(&mut self, item: &PreReleaseIdentifier) {
82+
self.extra_core.push(match item {
83+
PreReleaseIdentifier::String(s) => Component::String(s.clone()),
84+
PreReleaseIdentifier::Integer(n) => Component::Integer(*n),
85+
});
86+
}
87+
88+
fn process(mut self, pr: &[PreReleaseIdentifier]) -> ProcessResult {
89+
let mut i = 0;
90+
while i < pr.len() {
91+
if self.try_special_pattern(pr, i) {
92+
i += 2;
93+
} else if let PreReleaseIdentifier::String(label) = &pr[i] {
94+
if !self.try_pre_release_pattern(label, None) {
95+
self.add_regular_component(&pr[i]);
96+
}
97+
i += 1;
98+
} else {
99+
self.add_regular_component(&pr[i]);
100+
i += 1;
101+
}
102+
}
103+
(
104+
self.pre_release,
105+
self.extra_core,
106+
self.epoch,
107+
self.post,
108+
self.dev,
109+
)
110+
}
111+
}
112+
6113
impl From<SemVer> for Zerv {
7114
fn from(semver: SemVer) -> Self {
8115
let build = semver
@@ -19,99 +126,11 @@ impl From<SemVer> for Zerv {
19126
})
20127
.unwrap_or_default();
21128

22-
let (pre_release, extra_core, epoch, post, dev) = if let Some(pr) = &semver.pre_release {
23-
let mut pre_release = None;
24-
let mut extra_core = Vec::new();
25-
let mut epoch = None;
26-
let mut post = None;
27-
let mut dev = None;
28-
let mut skip_next = false;
29-
30-
for (i, item) in pr.iter().enumerate() {
31-
if skip_next {
32-
skip_next = false;
33-
continue;
34-
}
35-
36-
// Check for epoch+number pattern
37-
if i + 1 < pr.len()
38-
&& let (PreReleaseIdentifier::String(label), PreReleaseIdentifier::Integer(num)) =
39-
(item, &pr[i + 1])
40-
&& label == "epoch"
41-
&& epoch.is_none()
42-
{
43-
epoch = Some(*num);
44-
extra_core.push(Component::VarField("epoch".to_string()));
45-
skip_next = true;
46-
continue;
47-
}
48-
49-
// Check for dev+number pattern
50-
if i + 1 < pr.len()
51-
&& let (PreReleaseIdentifier::String(label), PreReleaseIdentifier::Integer(num)) =
52-
(item, &pr[i + 1])
53-
&& label == "dev"
54-
&& dev.is_none()
55-
{
56-
dev = Some(*num);
57-
extra_core.push(Component::VarField("dev".to_string()));
58-
skip_next = true;
59-
continue;
60-
}
61-
62-
// Check for post+number pattern
63-
if i + 1 < pr.len()
64-
&& let (PreReleaseIdentifier::String(label), PreReleaseIdentifier::Integer(num)) =
65-
(item, &pr[i + 1])
66-
&& label == "post"
67-
&& post.is_none()
68-
{
69-
post = Some(*num);
70-
extra_core.push(Component::VarField("post".to_string()));
71-
skip_next = true;
72-
continue;
73-
}
74-
75-
// Check for keyword+number pattern
76-
if i + 1 < pr.len()
77-
&& let (PreReleaseIdentifier::String(label), PreReleaseIdentifier::Integer(num)) =
78-
(item, &pr[i + 1])
79-
&& let Some(normalized_label) = normalize_pre_release_label(label)
80-
&& pre_release.is_none()
81-
{
82-
pre_release = Some(PreReleaseVar {
83-
label: normalized_label,
84-
number: Some(*num),
85-
});
86-
extra_core.push(Component::VarField("pre_release".to_string()));
87-
skip_next = true;
88-
continue;
89-
}
90-
91-
// Check for keyword-only pattern
92-
if let PreReleaseIdentifier::String(label) = item
93-
&& let Some(normalized_label) = normalize_pre_release_label(label)
94-
&& pre_release.is_none()
95-
{
96-
pre_release = Some(PreReleaseVar {
97-
label: normalized_label,
98-
number: None,
99-
});
100-
extra_core.push(Component::VarField("pre_release".to_string()));
101-
continue;
102-
}
103-
104-
// Regular component
105-
extra_core.push(match item {
106-
PreReleaseIdentifier::String(s) => Component::String(s.clone()),
107-
PreReleaseIdentifier::Integer(n) => Component::Integer(*n),
108-
});
109-
}
110-
111-
(pre_release, extra_core, epoch, post, dev)
112-
} else {
113-
(None, Vec::new(), None, None, None)
114-
};
129+
let (pre_release, extra_core, epoch, post, dev): ProcessResult = semver
130+
.pre_release
131+
.as_ref()
132+
.map(|pr| PreReleaseProcessor::new().process(pr))
133+
.unwrap_or_default();
115134

116135
Zerv {
117136
schema: ZervSchema {

0 commit comments

Comments
 (0)