Configuration¶
scd uses configuration file to get information on settings, search/replacement patterns and files to manage.
As you got from Install from Cheese Shop, scd can parse TOML, YAML and JSON configuration files. So first we need to elaborate a little bit on how to create required configuration.
Configuration Formats¶
Yes, 3 formats, but in most cases all three formats are possible to reduce to equialent JSON. Here are examples of all 3 formats, which are totally equialent.
YAML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | version:
number: 1.2.3
scheme: semver
search_patterns:
full: "{{ full }}"
replacement_patterns:
full: "{{ full }}"
defaults:
search: full
replace: full
files:
setup.py:
- default
|
TOML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [version]
number = "1.2.3"
scheme = "semver"
[search_patterns]
full = "{{ full }}"
[replacement_patterns]
full = "{{ full }}"
[defaults]
search = "full"
replace = "full"
[files]
"setup.py" = ["default"]
|
JSON:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | {
"version": {
"number": "1.2.3",
"scheme": "semver"
},
"search_patterns": {
"full": "{{ full }}"
},
"replacement_patterns": {
"full": "{{ full }}"
},
"defaults": {
"search": "full",
"replace": "full"
},
"files": {
"setup.py": ["default"]
}
}
|
I hope you get an idea: all these formats are representing the same datastructure. If you are familiar with JSON Schema, you may find that useful:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | {
"$schema": "http://json-schema.org/draft-04/schema",
"type": "object",
"required": ["version", "defaults", "files"],
"properties": {
"config": {
"type": "number",
"minimum": 1,
"multipleOf": 1.0
},
"version": {
"type": "object",
"required": ["scheme", "number"],
"properties": {
"scheme": {
"type": "string",
"enum": ["pep440", "semver", "git_pep440", "git_semver"]
},
"number": {
"oneOf": [
{"type": "number"},
{"type": "string"}
]
}
}
},
"files": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"oneOf": [
{"type": "string", "enum": ["default"]},
{
"type": "object",
"properties": {
"search": {"type": "string"},
"search_raw": {"type": "string"},
"replace": {"type": "string"},
"replace_raw": {"type": "string"}
},
"anyOf": [
{
"required": ["search"],
"not": {"required": ["search_raw"]}
},
{
"required": ["search_raw"],
"not": {"required": ["search"]}
},
{
"required": ["replace"],
"not": {"required": ["replace_raw"]}
},
{
"required": ["replace_raw"],
"not": {"required": ["replace"]}
}
]
}
]
}
}
},
"search_patterns": {
"type": "object",
"additionalProperties": {"type": "string"}
},
"replacement_paterns": {
"type": "object",
"additionalProperties": {"type": "string"}
},
"groups": {
"type": "object",
"additionalProperties": {"type": "string"}
},
"defaults": {
"type": "object",
"properties": {
"search": {"type": "string"},
"replacement": {"type": "string"}
},
"additionalProperties": false
}
}
}
|
Please be noticed that it is possible to extend allowed schemes with external entrypoints but PEP 440 and SemVer are supported out of box.
Examples¶
For simplicity, I will put examples here in YAML but as you already understand, they could be easily made with any other format.
Full Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | config: 1
version:
number: 1.0.1
scheme: semver
search_patterns:
full: "{{ semver }}"
vfull: "v{{ semver }}"
major_minor_block: "\\d+\\.\\d+(?=\\s\\#\\sBUMPVERSION)"
replacement_patterns:
full: "{{ full }}"
major_minor: "{{ major }}.{{ minor }}"
major_minor_p: "{{ major }}.{{ minor }}{% if patch %}.{{ patch }}{% endif %}"
defaults:
search: full
replace: full
groups:
code: 'scd/.*?\.py'
docs: 'docs/.*?'
files:
setup.py:
- search_raw: "(?>=version\\s=\\s\\\"){{ full }}"
docs/conf.py:
- default
- search: vfull
replace: major_minor_p
- search: major_minor_block
replace_raw: "{{ next_major }}"
|
Shortest Example¶
1 2 3 4 5 6 7 8 9 10 11 | version:
number: 1.0.1
scheme: semver
defaults:
search: semver
replace: base
files:
setup.py:
- default
|
So, as you can see, config can be large and can be small. It is up to you what to choose.
Parameters¶
From examples above you may get an idea that some parameters are
optionals, some mandatory. Mandatory parameters are version
,
defaults
and files
. All others are optionals.
Also, you may notice Mustache-like strings like {{ something }}
.
Your guessing is correct, it is Jinja2
templates. Template context variables are depended on choosen version
scheme, you can get a list of them in Predefined Template Context.
config
¶
config
is a numeric version (integers, please) of the config format.
This is the first field processed by scd therefore it is possible to
have absolutely different schemas in future.
This field is responsible for config schema version. Sometimes (probably in future) we will bring (definitely will) some non-backward compatible changes in schema and we will differ configs by numbers.
This field is optional in 1.x versions, it implicitly equal to 1.
version
¶
Version block defines a settings, related to versioning strategy.
scd won’t calculate version for you, you need to set base version by your own. Some may consider that as inconvenience (if you have latest version 0.1.0, it is good to have next one as 0.1.1 calculated automatically), but I belive this is for the greatest good (struggling to force your smartass versioner to have next version 0.2 is way more inconvenient, than setting explicit one).
This block has 2 mandatory parameters and 0 optionals.
Parameter | Type | Example | Description |
---|---|---|---|
number | string | 1.2.3 | This parameter defines basic version you are developing. Upcoming planned version. For example, you’ve just released version 1.3.0. What is the next version? Basically, nobody knows. It might be 1.3.1, it might be 1.4.0 or even 2.0.0. Seriously, it is totally up to your release management and branching strategy. This number is planned version, not released one. Planned. And all versions, calculated by scd will use that number as a base. So in templates
you may find |
scheme | string | semver | The name of the scheme your are using for versioning. scd will parse version numbers according to that parameter. So, all these
by default, scd supports PEP 440 and semver schemes. Their codenames are
User can define his own schemes using entrypoints-based plugin mechanism. Please
check documentation for |
search_patterns
¶
Search patterns defines regular expression which are used to search a place in file where to replace.
scd works in line-mode fashion, similar to sed, so all
expressions applied to the line. Also, please be noticed that
due to some implementation details, all expression will be
compiled with re.VERBOSE
and re.UNICODE
.
If you are not from Python world, please check re documentation.
Important
Please check documentation on re.VERBOSE. Seriously, if you do not know what it is, go and read.
This block should have a simple mapping, where key is the name of the pattern and value is regular expression, understandable by Python.
There are several predefined search templates are available:
pep440
semver
git_pep440
git_semver
They are matching version in the format, allowed by semver or PEP440. If you have your own versioning available as plugin, it will be here also. Since all of them are defined, there is no need to define them on your own. But if you define pattern with such name in that section, default one will be, obviously, overriden.
Also, to simplify composition of your own patterns, these names are
available as template context variables in search patterns. In other
words, pattern like v{{ semver }}
is perfectly fine.
Important
scd will replace group 0 of the pattern. This is done intentionally to avoid possible ambiguity. In other word, it replaces whole pattern, not only some group. If you want to define regular expression more presicely, please use look-ahead and look-behind expressions.
replacement_patterns
¶
Replacement patterns are used to express version for the search pattern.
The same thing, this parameter is key/value mapping where key if the name of the pattern and value is Jinja2 template, used for replacement. For available context variables please check PEP440 and SemVer
There are 2 predefined replacement patterns:
Name | Equialent | Description |
---|---|---|
base | {{ base }} | Base version. Literally, the same stuff as you have in version/number block |
full | {{ full }} | Full version, generated by your scheme. The most complete and precise as possible. |
Of course, it is possible to override them in that section.
groups
¶
Sometimes you want to change versions only in some subset of files. This why you can group them in some optional groups and filter by these groups. So, let’s say you’ve defined groups code and docs. In that case, you can modify versions in docs only, without touching the code.
This is a mapping parameter. Key is the group name, value is regular expression. Each expression sets a path (or pathes) relative to the position of config file. The same story, as in files.
Important
scd will implicitly append $
to the pattern. Please do not use
^
and $
as start/end of the line - it just makes no sense.
defaults
¶
If you have a lot of files, sometimes you want to have some default replacement or search. This is because it is possible to postpone some parameter having default one.
This block has 2 mandatory parameters and 2 optionals.
Name | Description |
---|---|
search | This is a name of search pattern which should be used by default. |
replace | This is a name of default replacement pattern should be used by default. |
Please be noticed, that values are names, not raw patterns. Keys from
search_patterns
and replacement_patterns
.
files
¶
Files are the list of file structures which scd should worry about. If scd does not have a section in config file, it will ignore file even if it explicitly set in CLI. Well, because nobody knows how to manage unknown file.
This is a mapping between filenames and a list of search/replacements.
Filename is rather simple: it is POSIX path to the file, relative
to the config. POSIX means that separator is /
, not \
.
So if you have a filename docs/source/conf.py
, it will
work perfectly on Unix/OS X and Windows. On Windows, actually, scd
will interpret this path as docssourceconf.py
os it is
crossplatform. Another mentioned thing about filename is that it
is relative to the config file. So with file above and config file
path /home/username/project/.scd.yaml
, scd will process
/home/username/project/docs/source/conf.py
.
Search/replacements are the list with following rules:
Parameter | Description |
---|---|
search | The name of the search pattern from Please check search_patterns for details. Note: this is mutually exclusive with |
search_raw | The pattern to use. This is actual regular expression which can be used to define
some search pattern ad-hoc, without populating Please check search_patterns for details on how to compose such regular expressions. Note: this is mutually exclusive with |
replace | The name of the replacement pattern from Please check replacement_patterns for details. Note: this is mutually exclusive with |
replace_raw | The replacement template to use. This is actual Jinja2 template which can be used
to define some ad-hoc replacement without populating Please check replacement_patterns for details. Note: this is mutually exclusive with |
Please be noticed that at least something has to be defined. You may
postpone any parameter (no search
or search_raw
for example,
but if you define any, please remember about mutual exclusive groups,
mentioned in table), then parameters from defaults section will
be used. But do not keep element empty. There is special placeholder
default
for that. So if you want to use defaults only, please use
config like:
1 2 3 4 5 6 7 8 9 10 11 | version:
number: 1.0.1
scheme: semver
defaults:
search: semver
replace: base
files:
setup.py:
- default
|
In that case semver
search pattern and base
replacement will be
used for setup.py
.
Predefined Template Context¶
As it was previously mentioned, there are several predefined context variables which might be used in templates for search and replacements. Also, please remember, that these contexts are different: you cannot use context vars from replacements to make search pattern.
Search Context¶
Context Variable | Description |
---|---|
pep440 | This searches version number, valid according to PEP 440. |
git_pep440 | Same as pep440 . |
semver | This searches version number, valid according to semver. |
git_semver | Same as semver . |
Replacement Context¶
Replacement context is totally dependend on version scheme provided. Moreover, every scheme provides its own set of context variables, and it is possible that you have a scheme which is not version numbered (I worked with such scheme once, and it was not that bad as one can think).
Of course, there is a number of some predefined context variables for replacements, you may find them in replacement_patterns section.
For next sections we need to make some assumptions on versions.
Let’s pretend that we have version 1.2.0
in our config
file, using Git flavor of a scheme, operating on commit
ff5cff170e93ab4f7dd87437951c6646e297c538
which is 5 commits left
from latest version tag.
SemVer¶
Context Variable | Type | Value From Example | |
---|---|---|---|
base | string | 1.2.0 | |
full | string | 1.2.0-5+ff5cff1 | |
major | integer | 1 | |
next_major | integer | 2 | |
prev_major | integer | 0 | |
minor | integer | 2 | |
next_minor | integer | 3 | |
prev_minor | integer | 1 | |
patch | integer | 0 | |
next_patch | integer | 1 | |
prev_patch | integer | 0 | |
prerelase | string | 5 | |
next_prerelease | string | 6 | |
prev_prerelease | string | 4 | |
build | string | ff5cff1 | |
next_build | string | ff5cff2 | |
prev_build | string | ff5cff0 |
As you can see, this is rather trivial. The most interesting parts are
build and prerelase management. By default, scd will try to guess next
and previous parts (it increments latest number found in the string).
Sometimes it make sense (build5
for example), sometimes not (Git
commit hash) so please pay attention to your strategy.
PEP440¶
To show all possible values, let’s consider base version as 1.2.0rc1
.
Context Variable | Type | Value From Example | ||
---|---|---|---|---|
base | string | 1.2.0rc1 | ||
full | string | 1.2.0rc1.dev5+ff5cff1 | ||
maximum | string | 0!1.2.0rc1.post0.dev5+ff5cff1 | ||
epoch | integer | 0 | ||
major | integer | 1 | ||
next_major | integer | 2 | ||
prev_major | integer | 0 | ||
minor | integer | 2 | ||
next_minor | integer | 3 | ||
prev_minor | integer | 1 | ||
patch | integer | 0 | ||
next_patch | integer | 1 | ||
prev_patch | integer | 0 | ||
prerelase | integer | 1 | ||
prerelase_type | string | rc | ||
next_prerelease | integer | 2 | ||
prev_prerelease | integer | 0 | ||
dev | integer | 5 | ||
next_dev | integer | 6 | ||
prev_dev | integer | 4 | ||
post | integer | 0 | ||
next_post | integer | 1 | ||
prev_post | integer | 0 | ||
local | string | ff5cff1 |
So, more or less the same. The only difference is that full
won’t
display data which is 0 or empty. maximum
does.