fastskill_core/core/
version_bump.rs1use crate::core::service::ServiceError;
4use semver::Version;
5use std::path::Path;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum BumpType {
10 Major,
11 Minor,
12 Patch,
13}
14
15pub fn parse_version(version: &str) -> Result<Version, ServiceError> {
17 let version_str = version.strip_prefix('v').unwrap_or(version);
19
20 Version::parse(version_str)
21 .map_err(|e| ServiceError::Custom(format!("Invalid version '{}': {}", version, e)))
22}
23
24pub fn bump_version(version: &Version, bump_type: BumpType) -> Version {
26 match bump_type {
27 BumpType::Major => Version {
28 major: version.major + 1,
29 minor: 0,
30 patch: 0,
31 pre: semver::Prerelease::EMPTY,
32 build: semver::BuildMetadata::EMPTY,
33 },
34 BumpType::Minor => Version {
35 major: version.major,
36 minor: version.minor + 1,
37 patch: 0,
38 pre: semver::Prerelease::EMPTY,
39 build: semver::BuildMetadata::EMPTY,
40 },
41 BumpType::Patch => Version {
42 major: version.major,
43 minor: version.minor,
44 patch: version.patch + 1,
45 pre: semver::Prerelease::EMPTY,
46 build: semver::BuildMetadata::EMPTY,
47 },
48 }
49}
50
51pub fn update_skill_version(skill_path: &Path, new_version: &str) -> Result<(), ServiceError> {
53 let skill_project_path = skill_path.join("skill-project.toml");
54
55 if !skill_project_path.exists() {
56 #[derive(serde::Serialize)]
58 struct SkillProjectToml {
59 metadata: SkillProjectMetadata,
60 }
61
62 #[derive(serde::Serialize)]
63 struct SkillProjectMetadata {
64 version: String,
65 }
66
67 let new_skill_project = SkillProjectToml {
68 metadata: SkillProjectMetadata {
69 version: new_version.to_string(),
70 },
71 };
72 let content = toml::to_string_pretty(&new_skill_project).map_err(|e| {
73 ServiceError::Custom(format!("Failed to serialize skill-project.toml: {}", e))
74 })?;
75 std::fs::write(&skill_project_path, content).map_err(ServiceError::Io)?;
76 return Ok(());
77 }
78
79 let content = std::fs::read_to_string(&skill_project_path).map_err(ServiceError::Io)?;
80
81 #[derive(serde::Deserialize, serde::Serialize)]
83 struct SkillProjectToml {
84 #[serde(default)]
85 metadata: Option<SkillProjectMetadata>,
86 #[serde(default)]
87 dependencies: Option<toml::Value>,
88 }
89
90 #[derive(serde::Deserialize, serde::Serialize)]
91 struct SkillProjectMetadata {
92 version: String,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 name: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 description: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 author: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 tags: Option<Vec<String>>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 capabilities: Option<Vec<String>>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 download_url: Option<String>,
105 }
106
107 if let Ok(mut skill_project) = toml::from_str::<SkillProjectToml>(&content) {
108 if let Some(ref mut metadata) = skill_project.metadata {
109 metadata.version = new_version.to_string();
110 } else {
111 skill_project.metadata = Some(SkillProjectMetadata {
112 version: new_version.to_string(),
113 name: None,
114 description: None,
115 author: None,
116 tags: None,
117 capabilities: None,
118 download_url: None,
119 });
120 }
121 let content = toml::to_string_pretty(&skill_project).map_err(|e| {
122 ServiceError::Custom(format!("Failed to serialize skill-project.toml: {}", e))
123 })?;
124 std::fs::write(&skill_project_path, content).map_err(ServiceError::Io)?;
125 Ok(())
126 } else {
127 let new_skill_project = SkillProjectToml {
129 metadata: Some(SkillProjectMetadata {
130 version: new_version.to_string(),
131 name: None,
132 description: None,
133 author: None,
134 tags: None,
135 capabilities: None,
136 download_url: None,
137 }),
138 dependencies: None,
139 };
140 let content = toml::to_string_pretty(&new_skill_project).map_err(|e| {
141 ServiceError::Custom(format!("Failed to serialize skill-project.toml: {}", e))
142 })?;
143 std::fs::write(&skill_project_path, content).map_err(ServiceError::Io)?;
144 Ok(())
145 }
146}
147
148pub fn get_current_version(skill_path: &Path) -> Result<Option<String>, ServiceError> {
150 let skill_project_path = skill_path.join("skill-project.toml");
151
152 if !skill_project_path.exists() {
153 return Ok(None);
154 }
155
156 let content = std::fs::read_to_string(&skill_project_path).map_err(ServiceError::Io)?;
157
158 #[derive(serde::Deserialize)]
159 struct SkillProjectToml {
160 metadata: Option<SkillProjectMetadata>,
161 }
162
163 #[derive(serde::Deserialize)]
164 struct SkillProjectMetadata {
165 version: Option<String>,
166 }
167
168 if let Ok(skill_project) = toml::from_str::<SkillProjectToml>(&content) {
169 if let Some(metadata) = skill_project.metadata {
170 if let Some(version) = metadata.version {
171 if !version.is_empty() {
172 return Ok(Some(version));
173 }
174 }
175 }
176 }
177
178 Ok(None)
179}