Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75fdf8a822 | ||
|
|
59e040994b | ||
|
|
0848079db3 |
No files matched your search
@@ -0,0 +1,37 @@
|
||||
name: Update major version tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update-major-tag:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out release tag
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update floating major tag
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_REF: ${{ gitea.ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_tag="${RELEASE_REF#refs/tags/}"
|
||||
if [[ ! "$release_tag" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
echo "Refusing to update a major tag from invalid release tag: $release_tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
major_tag="v${BASH_REMATCH[1]}"
|
||||
git config user.name "Gitea Actions"
|
||||
git config user.email "actions@localhost"
|
||||
git tag --force --annotate "$major_tag" --message "Update $major_tag to $release_tag" "$release_tag"
|
||||
git push origin "refs/tags/$major_tag" --force
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
A forge-neutral composite action for preparing a versioned Frappe/ERPNext app before merging its release branch. It uses [`bump-my-version`](https://callowayproject.github.io/bump-my-version/) and ordinary Git commands, without `gh` or GitHub API calls.
|
||||
|
||||
The action compares `[tool.bumpversion].current_version` on the checked-out target branch with the configured base branch:
|
||||
The action compares the app's `__version__` on the checked-out target branch with the configured base branch:
|
||||
|
||||
- Equal: bump, commit, and optionally push the new version.
|
||||
- Target newer than base: do nothing, making PR synchronization events idempotent.
|
||||
@@ -13,22 +13,9 @@ The action compares `[tool.bumpversion].current_version` on the checked-out targ
|
||||
- A Linux runner with Bash, Git, and Python 3.11 or newer.
|
||||
- A clean checkout of the branch that should receive the version commit.
|
||||
- Persisted Git credentials with permission to push that branch.
|
||||
- Stable `MAJOR.MINOR.PATCH` versions.
|
||||
- A `bump-my-version` configuration that includes every version file.
|
||||
- A version file containing a stable `MAJOR.MINOR.PATCH` assignment such as `__version__ = "0.0.1"`.
|
||||
|
||||
Example `pyproject.toml` for a Frappe app:
|
||||
|
||||
```toml
|
||||
[tool.bumpversion]
|
||||
current_version = "0.0.1"
|
||||
commit = false
|
||||
tag = false
|
||||
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "erp_operations/__init__.py"
|
||||
search = '__version__ = "{current_version}"'
|
||||
replace = '__version__ = "{new_version}"'
|
||||
```
|
||||
No `bump-my-version` configuration is required in the consuming app. The action passes the current version, search/replace templates, and version file directly to the CLI.
|
||||
|
||||
## Gitea Actions usage
|
||||
|
||||
@@ -58,9 +45,10 @@ jobs:
|
||||
|
||||
- name: Prepare version
|
||||
id: version
|
||||
uses: Nurinda/bump-erp-app-version@v1
|
||||
# The absolute URL is required when Gitea's DEFAULT_ACTIONS_URL is "github".
|
||||
uses: https://gitea.cptckp.com/Nurinda/bump-erp-app-version@v1
|
||||
with:
|
||||
config-file: pyproject.toml
|
||||
version-file: erp_operations/__init__.py
|
||||
base-branch: main
|
||||
target-branch: develop
|
||||
bump: patch
|
||||
@@ -77,7 +65,7 @@ Gitea may suppress workflows caused by pushes authenticated with its built-in `G
|
||||
|
||||
| Input | Default | Description |
|
||||
|---|---|---|
|
||||
| `config-file` | `pyproject.toml` | `bump-my-version` TOML configuration |
|
||||
| `version-file` | required | App `__init__.py` containing the authoritative `__version__` |
|
||||
| `base-branch` | `main` | Branch providing the baseline version |
|
||||
| `target-branch` | `develop` | Checked-out branch receiving the commit |
|
||||
| `bump` | `patch` | `major`, `minor`, or `patch` |
|
||||
@@ -101,6 +89,19 @@ Gitea may suppress workflows caused by pushes authenticated with its built-in `G
|
||||
|
||||
The action does not force-push, create tags, publish releases, or call forge APIs. Concurrent release jobs are resolved safely by the remote rejecting a non-fast-forward push. Configure workflow-level concurrency if release PRs can overlap.
|
||||
|
||||
The configured `version-file` is the only version source. The action reads it from both branches and commits only the version change produced by `bump-my-version`.
|
||||
|
||||
## Releasing the action
|
||||
|
||||
Create and push an immutable semantic-version tag:
|
||||
|
||||
```bash
|
||||
git tag -a v1.1.0 -m "Release v1.1.0"
|
||||
git push origin v1.1.0
|
||||
```
|
||||
|
||||
The `Update major version tag` Gitea workflow validates the release tag and automatically moves the corresponding floating major tag (for example, `v1`) to the same commit. Consumers can continue using `Nurinda/bump-erp-app-version@v1` to receive compatible v1 releases.
|
||||
|
||||
## Development
|
||||
|
||||
Run the integration test:
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
name: Bump ERP app version
|
||||
description: Bump a Frappe/ERPNext app version on a release branch using bump-my-version
|
||||
inputs:
|
||||
config-file:
|
||||
description: Path to the bump-my-version TOML configuration
|
||||
required: false
|
||||
default: pyproject.toml
|
||||
version-file:
|
||||
description: App __init__.py containing a stable MAJOR.MINOR.PATCH __version__ assignment
|
||||
required: true
|
||||
base-branch:
|
||||
description: Branch whose version is used as the release baseline
|
||||
required: false
|
||||
@@ -61,7 +60,7 @@ runs:
|
||||
id: bump
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_CONFIG_FILE: ${{ inputs.config-file }}
|
||||
INPUT_VERSION_FILE: ${{ inputs.version-file }}
|
||||
INPUT_BASE_BRANCH: ${{ inputs.base-branch }}
|
||||
INPUT_TARGET_BRANCH: ${{ inputs.target-branch }}
|
||||
INPUT_BUMP: ${{ inputs.bump }}
|
||||
|
||||
+12
-8
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
: "${INPUT_CONFIG_FILE:?config-file is required}"
|
||||
: "${INPUT_VERSION_FILE:?version-file is required}"
|
||||
: "${INPUT_BASE_BRANCH:?base-branch is required}"
|
||||
: "${INPUT_TARGET_BRANCH:?target-branch is required}"
|
||||
: "${INPUT_BUMP:?bump is required}"
|
||||
@@ -23,8 +23,8 @@ case "${INPUT_BUMP}" in
|
||||
*) echo "bump must be major, minor, or patch" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
if [[ ! -f "${INPUT_CONFIG_FILE}" ]]; then
|
||||
echo "Configuration file not found: ${INPUT_CONFIG_FILE}" >&2
|
||||
if [[ ! -f "${INPUT_VERSION_FILE}" ]]; then
|
||||
echo "Version file not found: ${INPUT_VERSION_FILE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -44,8 +44,8 @@ git fetch "${INPUT_REMOTE}" \
|
||||
|
||||
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
base_ref="refs/remotes/${INPUT_REMOTE}/${INPUT_BASE_BRANCH}"
|
||||
current_version=$(python3 "${script_dir}/read_version.py" "${INPUT_CONFIG_FILE}")
|
||||
base_version=$(python3 "${script_dir}/read_version.py" "${INPUT_CONFIG_FILE}" --ref "${base_ref}")
|
||||
current_version=$(python3 "${script_dir}/read_version.py" "${INPUT_VERSION_FILE}")
|
||||
base_version=$(python3 "${script_dir}/read_version.py" "${INPUT_VERSION_FILE}" --ref "${base_ref}")
|
||||
|
||||
comparison=$(python3 - "${current_version}" "${base_version}" <<'PY'
|
||||
import re
|
||||
@@ -91,13 +91,17 @@ git config user.email "${INPUT_GIT_USER_EMAIL}"
|
||||
|
||||
message=${INPUT_COMMIT_MESSAGE//\{version\}/\{new_version\}}
|
||||
"${venv_dir}/bin/bump-my-version" bump \
|
||||
--config-file "${INPUT_CONFIG_FILE}" \
|
||||
--current-version "${current_version}" \
|
||||
--search '__version__ = "{current_version}"' \
|
||||
--replace '__version__ = "{new_version}"' \
|
||||
--no-configured-files \
|
||||
--commit \
|
||||
--no-tag \
|
||||
--message "${message}" \
|
||||
"${INPUT_BUMP}"
|
||||
"${INPUT_BUMP}" \
|
||||
"${INPUT_VERSION_FILE}"
|
||||
|
||||
new_version=$(python3 "${script_dir}/read_version.py" "${INPUT_CONFIG_FILE}")
|
||||
new_version=$(python3 "${script_dir}/read_version.py" "${INPUT_VERSION_FILE}")
|
||||
commit=$(git rev-parse HEAD)
|
||||
|
||||
if [[ "${INPUT_PUSH}" == "true" ]]; then
|
||||
|
||||
+13
-16
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read bump-my-version's current_version from a local file or Git ref."""
|
||||
"""Read a Frappe app's stable __version__ from a local file or Git ref."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
import tomllib
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("config_file")
|
||||
parser.add_argument("version_file")
|
||||
parser.add_argument("--ref")
|
||||
return parser.parse_args()
|
||||
|
||||
@@ -20,24 +20,21 @@ def main() -> None:
|
||||
try:
|
||||
if args.ref:
|
||||
content = subprocess.check_output(
|
||||
["git", "show", f"{args.ref}:{args.config_file}"],
|
||||
["git", "show", f"{args.ref}:{args.version_file}"],
|
||||
text=True,
|
||||
)
|
||||
else:
|
||||
with open(args.config_file, "rb") as config_file:
|
||||
content = config_file.read()
|
||||
with open(args.version_file, encoding="utf-8") as version_file:
|
||||
content = version_file.read()
|
||||
except (OSError, subprocess.CalledProcessError) as error:
|
||||
raise SystemExit(f"Could not load {args.config_file}: {error}") from error
|
||||
raise SystemExit(f"Could not load {args.version_file}: {error}") from error
|
||||
|
||||
try:
|
||||
version = tomllib.loads(content.decode())["tool"]["bumpversion"]["current_version"]
|
||||
except (KeyError, TypeError, UnicodeDecodeError, tomllib.TOMLDecodeError) as error:
|
||||
match = re.search(r'^__version__ = "(\d+\.\d+\.\d+)"$', content, re.MULTILINE)
|
||||
if not match:
|
||||
raise SystemExit(
|
||||
f"Could not read tool.bumpversion.current_version from {args.config_file}: {error}"
|
||||
) from error
|
||||
|
||||
if not isinstance(version, str):
|
||||
raise SystemExit("tool.bumpversion.current_version must be a string")
|
||||
print(version)
|
||||
f"Could not read a stable MAJOR.MINOR.PATCH __version__ from {args.version_file}"
|
||||
)
|
||||
print(match.group(1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+5
-11
@@ -12,15 +12,9 @@ git config user.name Test
|
||||
git config user.email test@example.com
|
||||
mkdir erp_operations
|
||||
cat > pyproject.toml <<'TOML'
|
||||
[tool.bumpversion]
|
||||
current_version = "0.0.1"
|
||||
commit = false
|
||||
tag = false
|
||||
|
||||
[[tool.bumpversion.files]]
|
||||
filename = "erp_operations/__init__.py"
|
||||
search = '__version__ = "{current_version}"'
|
||||
replace = '__version__ = "{new_version}"'
|
||||
[project]
|
||||
name = "erp_operations"
|
||||
dynamic = ["version"]
|
||||
TOML
|
||||
printf '%s\n' '__version__ = "0.0.1"' > erp_operations/__init__.py
|
||||
git add .
|
||||
@@ -30,7 +24,7 @@ git push -qu origin main
|
||||
git switch -qc develop
|
||||
git push -qu origin develop
|
||||
|
||||
export INPUT_CONFIG_FILE=pyproject.toml
|
||||
export INPUT_VERSION_FILE=erp_operations/__init__.py
|
||||
export INPUT_BASE_BRANCH=main
|
||||
export INPUT_TARGET_BRANCH=develop
|
||||
export INPUT_BUMP=patch
|
||||
@@ -44,7 +38,7 @@ export RUNNER_TEMP="${test_root}"
|
||||
export GITHUB_OUTPUT="${test_root}/output"
|
||||
|
||||
"${repo_root}/scripts/bump.sh"
|
||||
grep -q '^current_version = "0.0.2"$' pyproject.toml
|
||||
! grep -q '^\[tool.bumpversion\]' pyproject.toml
|
||||
grep -q '^__version__ = "0.0.2"$' erp_operations/__init__.py
|
||||
grep -q '^bumped=true$' "${GITHUB_OUTPUT}"
|
||||
grep -q '^previous-version=0.0.1$' "${GITHUB_OUTPUT}"
|
||||
|
||||
Reference in new issue
Block a user