intial commit
Test action / integration (push) Successful in 11s

This commit is contained in:
NikoKS committed 2026-08-26 22:59:40 +07:00
commit 88bc7844e3
7 files changed
+446

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
name: Test action
on:
push:
pull_request:
permissions:
contents: read
jobs:
integration:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
- name: Run integration test
run: ./tests/integration.sh
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Nurinda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+112
View File
@@ -0,0 +1,112 @@
# Bump ERP App Version
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:
- Equal: bump, commit, and optionally push the new version.
- Target newer than base: do nothing, making PR synchronization events idempotent.
- Target older than base: fail and require branch synchronization.
## Requirements
- 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.
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}"'
```
## Gitea Actions usage
```yaml
name: Prepare application version
on:
pull_request:
branches: [main]
types: [opened, reopened, synchronize]
permissions:
contents: write
pull-requests: read
jobs:
version:
if: ${{ gitea.head_ref == 'develop' }}
runs-on: ubuntu-latest
steps:
- name: Check out develop
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
with:
ref: develop
fetch-depth: 0
token: ${{ secrets.GITEA_TOKEN }}
- name: Prepare version
id: version
uses: Nurinda/bump-erp-app-version@v1
with:
config-file: pyproject.toml
base-branch: main
target-branch: develop
bump: patch
git-user-name: ERP Operations Release Bot
git-user-email: it@nurinda.co.id
- name: Report version
run: echo "${{ steps.version.outputs.previous-version }} -> ${{ steps.version.outputs.current-version }}"
```
Gitea may suppress workflows caused by pushes authenticated with its built-in `GITEA_TOKEN`. If CI checks must rerun on the generated commit, pass a narrowly scoped bot repository token to `actions/checkout` instead.
## Inputs
| Input | Default | Description |
|---|---|---|
| `config-file` | `pyproject.toml` | `bump-my-version` TOML configuration |
| `base-branch` | `main` | Branch providing the baseline version |
| `target-branch` | `develop` | Checked-out branch receiving the commit |
| `bump` | `patch` | `major`, `minor`, or `patch` |
| `remote` | `origin` | Git remote used for fetch and push |
| `commit-message` | `chore(release): prepare v{version}` | Version commit message |
| `git-user-name` | `ERP App Release Bot` | Git commit identity |
| `git-user-email` | `actions@localhost` | Git commit identity |
| `bump-my-version-version` | `1.5.1` | Exact package version installed in an isolated environment |
| `push` | `true` | Whether to push the created commit |
## Outputs
| Output | Description |
|---|---|
| `bumped` | `true` when a commit was created |
| `previous-version` | Version before the action ran |
| `current-version` | Version after the action ran |
| `commit` | Created commit SHA, empty for a no-op |
## Safety behavior
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.
## Development
Run the integration test:
```bash
./tests/integration.sh
```
The test creates a temporary Git remote and verifies bumping, committing, pushing, and idempotent reruns.
+77
View File
@@ -0,0 +1,77 @@
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
base-branch:
description: Branch whose version is used as the release baseline
required: false
default: main
target-branch:
description: Checked-out branch that receives the version commit
required: false
default: develop
bump:
description: Version component passed to bump-my-version
required: false
default: patch
remote:
description: Git remote used to fetch and push
required: false
default: origin
commit-message:
description: Commit message; {version} is replaced with the new version
required: false
default: "chore(release): prepare v{version}"
git-user-name:
description: Author and committer name for the version commit
required: false
default: ERP App Release Bot
git-user-email:
description: Author and committer email for the version commit
required: false
default: actions@localhost
bump-my-version-version:
description: Pinned bump-my-version package version to install
required: false
default: "1.5.1"
push:
description: Push the version commit to target-branch
required: false
default: "true"
outputs:
bumped:
description: Whether this run created a version commit
value: ${{ steps.bump.outputs.bumped }}
previous-version:
description: Version before this action ran
value: ${{ steps.bump.outputs.previous-version }}
current-version:
description: Version after this action ran
value: ${{ steps.bump.outputs.current-version }}
commit:
description: Created commit SHA, or an empty string when no bump was needed
value: ${{ steps.bump.outputs.commit }}
runs:
using: composite
steps:
- name: Compare, bump, commit, and push
id: bump
shell: bash
env:
INPUT_CONFIG_FILE: ${{ inputs.config-file }}
INPUT_BASE_BRANCH: ${{ inputs.base-branch }}
INPUT_TARGET_BRANCH: ${{ inputs.target-branch }}
INPUT_BUMP: ${{ inputs.bump }}
INPUT_REMOTE: ${{ inputs.remote }}
INPUT_COMMIT_MESSAGE: ${{ inputs.commit-message }}
INPUT_GIT_USER_NAME: ${{ inputs.git-user-name }}
INPUT_GIT_USER_EMAIL: ${{ inputs.git-user-email }}
INPUT_BUMP_MY_VERSION_VERSION: ${{ inputs.bump-my-version-version }}
INPUT_PUSH: ${{ inputs.push }}
run: ${{ github.action_path }}/scripts/bump.sh
branding:
icon: chevrons-up
color: blue
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
set -euo pipefail
: "${INPUT_CONFIG_FILE:?config-file is required}"
: "${INPUT_BASE_BRANCH:?base-branch is required}"
: "${INPUT_TARGET_BRANCH:?target-branch is required}"
: "${INPUT_BUMP:?bump is required}"
: "${INPUT_REMOTE:?remote is required}"
: "${INPUT_COMMIT_MESSAGE:?commit-message is required}"
: "${INPUT_GIT_USER_NAME:?git-user-name is required}"
: "${INPUT_GIT_USER_EMAIL:?git-user-email is required}"
: "${INPUT_BUMP_MY_VERSION_VERSION:?bump-my-version-version is required}"
: "${INPUT_PUSH:?push is required}"
: "${GITHUB_OUTPUT:?GITHUB_OUTPUT is required}"
case "${INPUT_PUSH}" in
true | false) ;;
*) echo "push must be 'true' or 'false'" >&2; exit 1 ;;
esac
case "${INPUT_BUMP}" in
major | minor | patch) ;;
*) 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
exit 1
fi
if [[ -n "$(git status --porcelain)" ]]; then
echo "Working tree must be clean before bumping the version" >&2
exit 1
fi
current_branch=$(git branch --show-current)
if [[ "${current_branch}" != "${INPUT_TARGET_BRANCH}" ]]; then
echo "Expected checked-out branch '${INPUT_TARGET_BRANCH}', found '${current_branch:-detached HEAD}'" >&2
exit 1
fi
git fetch "${INPUT_REMOTE}" \
"${INPUT_BASE_BRANCH}:refs/remotes/${INPUT_REMOTE}/${INPUT_BASE_BRANCH}"
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}")
comparison=$(python3 - "${current_version}" "${base_version}" <<'PY'
import re
import sys
pattern = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$")
versions = []
for value in sys.argv[1:]:
match = pattern.fullmatch(value)
if not match:
raise SystemExit(f"Version must use stable MAJOR.MINOR.PATCH format: {value}")
versions.append(tuple(map(int, match.groups())))
print((versions[0] > versions[1]) - (versions[0] < versions[1]))
PY
)
if [[ "${comparison}" == "1" ]]; then
echo "Version ${current_version} is already prepared (base: ${base_version})"
{
echo "bumped=false"
echo "previous-version=${current_version}"
echo "current-version=${current_version}"
echo "commit="
} >> "${GITHUB_OUTPUT}"
exit 0
fi
if [[ "${comparison}" == "-1" ]]; then
echo "Target branch version ${current_version} is older than base branch version ${base_version}" >&2
echo "Synchronize ${INPUT_TARGET_BRANCH} with ${INPUT_BASE_BRANCH} before releasing" >&2
exit 1
fi
venv_dir=$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/bump-erp-app-version.XXXXXX")
trap 'rm -rf "${venv_dir}"' EXIT
python3 -m venv "${venv_dir}"
"${venv_dir}/bin/pip" install --disable-pip-version-check \
"bump-my-version==${INPUT_BUMP_MY_VERSION_VERSION}"
git config user.name "${INPUT_GIT_USER_NAME}"
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}" \
--commit \
--no-tag \
--message "${message}" \
"${INPUT_BUMP}"
new_version=$(python3 "${script_dir}/read_version.py" "${INPUT_CONFIG_FILE}")
commit=$(git rev-parse HEAD)
if [[ "${INPUT_PUSH}" == "true" ]]; then
git push "${INPUT_REMOTE}" "HEAD:${INPUT_TARGET_BRANCH}"
fi
{
echo "bumped=true"
echo "previous-version=${current_version}"
echo "current-version=${new_version}"
echo "commit=${commit}"
} >> "${GITHUB_OUTPUT}"
echo "Prepared ${current_version} -> ${new_version} (${commit})"
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Read bump-my-version's current_version from a local file or Git ref."""
from __future__ import annotations
import argparse
import subprocess
import tomllib
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("config_file")
parser.add_argument("--ref")
return parser.parse_args()
def main() -> None:
args = parse_args()
try:
if args.ref:
content = subprocess.check_output(
["git", "show", f"{args.ref}:{args.config_file}"],
)
else:
with open(args.config_file, "rb") as config_file:
content = config_file.read()
except (OSError, subprocess.CalledProcessError) as error:
raise SystemExit(f"Could not load {args.config_file}: {error}") from error
try:
version = tomllib.loads(content.decode())["tool"]["bumpversion"]["current_version"]
except (KeyError, TypeError, UnicodeDecodeError, tomllib.TOMLDecodeError) as error:
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)
if __name__ == "__main__":
main()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
test_root=$(mktemp -d)
trap 'rm -rf "${test_root}"' EXIT
git init --bare -q "${test_root}/remote.git"
git init -q -b main "${test_root}/app"
cd "${test_root}/app"
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}"'
TOML
printf '%s\n' '__version__ = "0.0.1"' > erp_operations/__init__.py
git add .
git commit -qm initial
git remote add origin "${test_root}/remote.git"
git push -qu origin main
git switch -qc develop
git push -qu origin develop
export INPUT_CONFIG_FILE=pyproject.toml
export INPUT_BASE_BRANCH=main
export INPUT_TARGET_BRANCH=develop
export INPUT_BUMP=patch
export INPUT_REMOTE=origin
export INPUT_COMMIT_MESSAGE='chore(release): prepare v{version}'
export INPUT_GIT_USER_NAME='ERP App Release Bot'
export INPUT_GIT_USER_EMAIL='actions@example.com'
export INPUT_BUMP_MY_VERSION_VERSION=1.5.1
export INPUT_PUSH=true
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 '^__version__ = "0.0.2"$' erp_operations/__init__.py
grep -q '^bumped=true$' "${GITHUB_OUTPUT}"
grep -q '^previous-version=0.0.1$' "${GITHUB_OUTPUT}"
grep -q '^current-version=0.0.2$' "${GITHUB_OUTPUT}"
[[ "$(git log -1 --format=%s)" == "chore(release): prepare v0.0.2" ]]
[[ "$(git rev-parse HEAD)" == "$(git --git-dir="${test_root}/remote.git" rev-parse develop)" ]]
: > "${GITHUB_OUTPUT}"
"${repo_root}/scripts/bump.sh"
grep -q '^bumped=false$' "${GITHUB_OUTPUT}"
[[ "$(git rev-list --count main..develop)" == "1" ]]
echo "Integration test passed"