Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
outputs:
sem-ver: ${{ steps.determine-version.outputs.GitVersion_SemVer }}
pre-release-label: ${{ steps.determine-version.outputs.GitVersion_PreReleaseLabel }}
version-source-sha: ${{ steps.determine-version.outputs.GitVersion_VersionSourceSha }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
Expand All @@ -33,13 +34,40 @@ jobs:

- name: Install git-versioner
run: |
curl -L -o git-versioner https://github.com/Crown0815/git-versioner/releases/download/v0.6.0/git-versioner-x86_64-unknown-linux-gnu
curl -L -o git-versioner https://github.com/Crown0815/git-versioner/releases/download/v0.8.0/git-versioner-x86_64-unknown-linux-gnu
chmod +x git-versioner

- name: Determine Version
id: determine-version
run: ./git-versioner ${{ github.event.inputs.as-pre-release && '' || '--as-release' }}

determine-changelog:
name: Determine Changelog
runs-on: ubuntu-latest
outputs:
changelog: ${{ steps.determine-changelog.outputs.changelog }}
needs:
determine-version
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Generate Changelog
id: determine-changelog
run: |-
export PATH="$PATH:/root/.dotnet/tools"
dotnet tool install --global ConventionalChangelog --version 0.11.0
CHANGELOG=$(changelog --skip-title --show-hash --reference-commit ${{ needs.determine-version.outputs.version-source-sha }} "${{ github.workspace }}")

echo "changelog<<EOF_STEFFIMAXMAGDALENA" >> "$GITHUB_OUTPUT"
echo "$CHANGELOG" >> "$GITHUB_OUTPUT"
echo "EOF_STEFFIMAXMAGDALENA" >> "$GITHUB_OUTPUT"

- name: Print Changelog
run: echo "${{ steps.determine-changelog.outputs.changelog }}"

build:
strategy:
fail-fast: false
Expand Down Expand Up @@ -134,13 +162,6 @@ jobs:
with:
toolchain: ${{ matrix.build.toolchain }}
targets: ${{ matrix.build.target }}
components: rustfmt, clippy

- name: Check format
run: cargo fmt -- --check

- name: Run clippy
run: cargo clippy -- -D warnings

- name: Set version in Cargo.toml
run: |
Expand Down Expand Up @@ -217,7 +238,7 @@ jobs:
if-no-files-found: error

release:
needs: [build, determine-version]
needs: [build, determine-version, determine-changelog]
runs-on: ubuntu-latest
steps:
- name: Download artifacts
Expand Down Expand Up @@ -255,4 +276,6 @@ jobs:
tag_name: "v${{ needs.determine-version.outputs.sem-ver }}"
draft: ${{ github.event.inputs.as-draft }}
prerelease: ${{ steps.determine-version.outputs.pre-release-label != '' }}
body: |
${{ needs.determine-changelog.outputs.changelog }}
fail_on_unmatched_files: true
61 changes: 37 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,37 @@ This command will output the calculated version string based on the repository's

For integration in scripts or CI/CD, capture the output for use in build artifacts or tags.

The command line options allow overwriting of configuration options using (see also [Configuration](#configuration))
The command line options allow overwriting of configuration options using (see also [Configuration](#configuration)) and some additional options:

```shell
--main-branch <MAIN_BRANCH>
--release-branch <RELEASE_BRANCH>
--feature-branch <FEATURE_BRANCH>
--tag-prefix <TAG_PREFIX>
--pre-release-tag <PRE_RELEASE_TAG>
```

Additionally, the following options are supported:

```shell

-p, --path <PATH>
-v, --verbose
-c, --config <CONFIG_FILE> Path to a configuration file (TOML or YAML)
-h, --help Print help
-V, --version Print version
-p, --path <PATH>
Path to the repository to calculate the version for
--main-branch <MAIN_BRANCH>
Regex to detect the main branch
--release-branch <RELEASE_BRANCH>
Regex to detect the release branch(es)
--feature-branch <FEATURE_BRANCH>
Regex to detect the feature branch(es)
--tag-prefix <TAG_PREFIX>
Regex to detect version tag(s)
--pre-release-tag <PRE_RELEASE_TAG>
Regex to detect pre-release version tag(s)
--continuous-delivery
Calculate version using continuous delivery mode
--commit-message-incrementing <COMMIT_MESSAGE_INCREMENTING>
Increment based on conventional commits (set to 'Enabled' or 'Disabled')
-a, --as-release
Forces release generation instead of pre-release
--show-config
Print effective configuration and exit
-v, --verbose

-c, --config <CONFIG_FILE>
Path to a configuration file (TOML or YAML)
-h, --help
Print help (see more with '--help')
-V, --version
Print version
```

For integration in scripts or CI/CD, capture the output for use in build artifacts or tags.
Expand All @@ -152,16 +164,17 @@ For integration in scripts or CI/CD, capture the output for use in build artifac

Git Versioner supports a YAML or TOML configuration file to customize its behavior.
Create a file named `.git-versioner.toml`, `.git-versioner.yaml`, or `.git-versioner.yml` in the repository root.
All fields are optional and will fall back to internal defaults if not specified.
All fields are optional and will fall back to internal defaults if not specified.

An example configuration is as follows:
The *default* configuration is as follows:

```yaml
MainBranch: "^trunk$"
ReleaseBranch: "^release/(?<BranchName>.+)$"
FeatureBranch: "feature/(?<BranchName>.+)$"
TagPrefix: "[vV]?"
PreReleaseTag: "pre"
MainBranch: ^(trunk|main|master)$
ReleaseBranch: ^releases?[/-](?<BranchName>.+)$
FeatureBranch: ^features?[/-](?<BranchName>.+)$
TagPrefix: '[vV]?'
PreReleaseTag: pre
CommitMessageIncrementing: Disabled
```

### Configuration Fields
Expand Down
106 changes: 65 additions & 41 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};

const DEFAULT_CONFIG_FILE_NAME: &str = ".git-versioner";
const CONFIG_FILE_EXTENSIONS: [&str; 3] = ["toml", "yaml", "yml"];

pub const MAIN_BRANCH: &str = r"^(trunk|main|master)$";
pub const RELEASE_BRANCH: &str = r"^releases?[/-](?<BranchName>.+)$";
pub const FEATURE_BRANCH: &str = r"^features?[/-](?<BranchName>.+)$";
Expand Down Expand Up @@ -73,49 +76,75 @@ pub struct ConfigurationFile {
pub feature_branch: Option<String>,
pub tag_prefix: Option<String>,
pub pre_release_tag: Option<String>,
// pub commit_message_incrementing: Option<String>,
pub commit_message_incrementing: Option<String>,
}

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
#[arg(short, long, value_parser)]
#[arg(
short,
long,
value_parser,
help = "Path to the repository to calculate the version for"
)]
path: Option<PathBuf>,

#[arg(long, value_parser)]
#[arg(long, value_parser, help = "Regex to detect the main branch")]
main_branch: Option<String>,

#[arg(long, value_parser)]
#[arg(long, value_parser, help = "Regex to detect the release branch(es)")]
release_branch: Option<String>,

#[arg(long, value_parser)]
#[arg(long, value_parser, help = "Regex to detect the feature branch(es)")]
feature_branch: Option<String>,

#[arg(long, value_parser)]
#[arg(long, value_parser, help = "Regex to detect version tag(s)")]
tag_prefix: Option<String>,

#[arg(long, value_parser)]
#[arg(
long,
value_parser,
help = "Regex to detect pre-release version tag(s)"
)]
pre_release_tag: Option<String>,

#[arg(long, value_parser)]
/// Calculate version using continuous delivery mode
#[arg(
long,
value_parser,
help = "Calculate version using continuous delivery mode"
)]
continuous_delivery: bool,

// #[arg(long, value_parser)]
// commit_message_incrementing: Option<String>,
/// Outputs effective git-versioner config in toml format
#[arg(long)]
#[arg(
long,
value_parser,
help = "Increment based on conventional commits ('Disabled' (default) or 'Enabled')",
long_help = r#"Increment considering conventional commits (values: 'Disabled' (default) or 'Enabled'):
- Disabled: Incrementation will be based on tags and release branches only.
After a release tag is created on the main branch (e.g. v1.2.0), the main branch will
automatically be bumped to the next minor version (e.g. v1.3.0).
- Enabled: Incrementation will be based on tags, release branches and commits.
Instead of bumping the minor version on the main branch after a feature release tag
(e.g. v1.2.0), only the patch version will be incremented (e.g. v1.2.1) until a `feat:`
commit is encountered or a release branch is created."#
)]
commit_message_incrementing: Option<String>,

#[arg(short, long, help = "Forces release generation instead of pre-release")]
as_release: bool,

#[arg(long, help = "Print effective configuration and exit")]
show_config: bool,

#[arg(short, long)]
verbose: bool,

#[arg(short, long)]
/// If the version is pre-release, generate release instead
as_release: bool,

/// Path to a configuration file (TOML or YAML)
#[arg(short = 'c', long = "config")]
#[arg(
short = 'c',
long = "config",
help = "Path to a configuration file (TOML or YAML)"
)]
config_file: Option<PathBuf>,
}

Expand Down Expand Up @@ -166,6 +195,19 @@ impl Configuration for DefaultConfig {
}

impl ConfigurationFile {
pub fn from_default_file() -> anyhow::Result<Self> {
let mut last_error: Option<anyhow::Error> = None;

for &ext in CONFIG_FILE_EXTENSIONS.iter() {
match Self::from_file(format!("{}.{}", DEFAULT_CONFIG_FILE_NAME, ext)) {
Ok(config) => return Ok(config),
Err(err) => last_error = Some(err),
}
}

Err(last_error.unwrap())
}

pub fn from_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let path = path.as_ref();
let extension = path
Expand All @@ -180,40 +222,24 @@ impl ConfigurationFile {
}
}

pub fn from_toml_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
fn from_toml_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let content = fs::read_to_string(path)?;
let config: Self = toml::from_str(&content)?;
Ok(config)
}

pub fn from_yaml_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
fn from_yaml_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let content = fs::read_to_string(path)?;
let config: Self = serde_yaml::from_str(&content)?;
Ok(config)
}

pub fn from_default_files() -> anyhow::Result<Self> {
let toml_path = Path::new(".git-versioner.toml");
let yaml_path = Path::new(".git-versioner.yaml");
let yml_path = Path::new(".git-versioner.yml");

if toml_path.exists() {
return Self::from_toml_file(toml_path);
} else if yaml_path.exists() {
return Self::from_yaml_file(yaml_path);
} else if yml_path.exists() {
return Self::from_yaml_file(yml_path);
}

Err(anyhow!("No configuration file found"))
}
}

pub fn load_configuration() -> anyhow::Result<ConfigurationLayers> {
let args = Args::parse();
let config = DefaultConfig::default();
let file = match &args.config_file {
None => ConfigurationFile::from_default_files(),
None => ConfigurationFile::from_default_file(),
Some(path) => ConfigurationFile::from_file(path),
}
.unwrap_or_default();
Expand Down Expand Up @@ -254,9 +280,7 @@ impl Configuration for ConfigurationLayers {
config_getter!(feature_branch, str, arg > file > default);
config_getter!(tag_prefix, str, arg > file > default);
config_getter!(pre_release_tag, str, arg > file > default);
fn commit_message_incrementing(&self) -> &str {
&self.config.commit_message_incrementing
}
config_getter!(commit_message_incrementing, str, arg > file > default);
config_getter!(continuous_delivery, bool, arg);
config_getter!(path, PathBuf, arg > default);
config_getter!(as_release, bool, arg);
Expand Down
Loading