mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'master' of https://github.com/inventree/InvenTree into webhook-2036
This commit is contained in:
commit
a344bc1ab2
@ -15,6 +15,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
- name: Check version number
|
||||
run: |
|
||||
python3 ci/check_version_number.py --dev
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
42
.github/workflows/docker_stable.yaml
vendored
Normal file
42
.github/workflows/docker_stable.yaml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
# Build and push latest docker image on push to master branch
|
||||
|
||||
name: Docker Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'stable'
|
||||
|
||||
jobs:
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
- name: Check version number
|
||||
run: |
|
||||
python3 ci/check_version_number.py --release
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and Push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./docker
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
target: production
|
||||
build-args:
|
||||
branch: stable
|
||||
repository: inventree/inventree
|
||||
tags: inventree/inventree:stable
|
||||
- name: Image Digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
@ -15,7 +15,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Check Release tag
|
||||
run: |
|
||||
python3 ci/check_version_number.py ${{ github.event.release.tag_name }}
|
||||
python3 ci/check_version_number.py --release --tag ${{ github.event.release.tag_name }}
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
20
.github/workflows/version.yaml
vendored
Normal file
20
.github/workflows/version.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Check that the version number format matches the current branch
|
||||
|
||||
name: Version Numbering
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- l10*
|
||||
|
||||
jobs:
|
||||
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
- name: Check version number
|
||||
run: |
|
||||
python3 ci/check_version_number.py --branch ${{ github.base_ref }}
|
@ -1,22 +1,102 @@
|
||||
Contributions to InvenTree are welcomed - please follow the guidelines below.
|
||||
Please read the contribution guidelines below, before submitting your first pull request to the InvenTree codebase.
|
||||
|
||||
## Feature Branches
|
||||
## Branches and Versioning
|
||||
|
||||
No pushing to master! New featues must be submitted in a separate branch (one branch per feature).
|
||||
InvenTree roughly follow the [GitLab flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html) branching style, to allow simple management of multiple tagged releases, short-lived branches, and development on the main branch.
|
||||
|
||||
## Include Migration Files
|
||||
### Version Numbering
|
||||
|
||||
InvenTree version numbering follows the [semantic versioning](https://semver.org/) specification.
|
||||
|
||||
### Master Branch
|
||||
|
||||
The HEAD of the "main" or "master" branch of InvenTree represents the current "latest" state of code development.
|
||||
|
||||
- All feature branches are merged into master
|
||||
- All bug fixes are merged into master
|
||||
|
||||
**No pushing to master:** New featues must be submitted as a pull request from a separate branch (one branch per feature).
|
||||
|
||||
#### Feature Branches
|
||||
|
||||
Feature branches should be branched *from* the *master* branch.
|
||||
|
||||
- One major feature per branch / pull request
|
||||
- Feature pull requests are merged back *into* the master branch
|
||||
- Features *may* also be merged into a release candidate branch
|
||||
|
||||
### Stable Branch
|
||||
|
||||
The HEAD of the "stable" branch represents the latest stable release code.
|
||||
|
||||
- Versioned releases are merged into the "stable" branch
|
||||
- Bug fix branches are made *from* the "stable" branch
|
||||
|
||||
#### Release Candidate Branches
|
||||
|
||||
- Release candidate branches are made from master, and merged into stable.
|
||||
- RC branches are targetted at a major/minor version e.g. "0.5"
|
||||
- When a release candidate branch is merged into *stable*, the release is tagged
|
||||
|
||||
#### Bugfix Branches
|
||||
|
||||
- If a bug is discovered in a tagged release version of InvenTree, a "bugfix" or "hotfix" branch should be made *from* that tagged release
|
||||
- When approved, the branch is merged back *into* stable, with an incremented PATCH number (e.g. 0.4.1 -> 0.4.2)
|
||||
- The bugfix *must* also be cherry picked into the *master* branch.
|
||||
|
||||
## Migration Files
|
||||
|
||||
Any required migration files **must** be included in the commit, or the pull-request will be rejected. If you change the underlying database schema, make sure you run `invoke migrate` and commit the migration files before submitting the PR.
|
||||
|
||||
*Note: A github action checks for unstaged migration files and will reject the PR if it finds any!*
|
||||
|
||||
## Testing
|
||||
## Unit Testing
|
||||
|
||||
Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage is decreased.
|
||||
Any new code should be covered by unit tests - a submitted PR may not be accepted if the code coverage for any new features is insufficient, or the overall code coverage is decreased.
|
||||
|
||||
The InvenTree code base makes use of [GitHub actions](https://github.com/features/actions) to run a suite of automated tests against the code base every time a new pull request is received. These actions include (but are not limited to):
|
||||
|
||||
- Checking Python and Javascript code against standard style guides
|
||||
- Running unit test suite
|
||||
- Automated building and pushing of docker images
|
||||
- Generating translation files
|
||||
|
||||
The various github actions can be found in the `./github/workflows` directory
|
||||
|
||||
## Code Style
|
||||
|
||||
Sumbitted Python code is automatically checked against PEP style guidelines. Locally you can run `invoke style` to ensure the style checks will pass, before submitting the PR.
|
||||
|
||||
## Documentation
|
||||
|
||||
New features or updates to existing features should be accompanied by user documentation. A PR with associated documentation should link to the matching PR at https://github.com/inventree/inventree-docs/
|
||||
|
||||
## Code Style
|
||||
## Translations
|
||||
|
||||
Sumbitted Python code is automatically checked against PEP style guidelines. Locally you can run `invoke style` to ensure the style checks will pass, before submitting the PR.
|
||||
Any user-facing strings *must* be passed through the translation engine.
|
||||
|
||||
- InvenTree code is written in English
|
||||
- User translatable strings are provided in English as the primary language
|
||||
- Secondary language translations are provided [via Crowdin](https://crowdin.com/project/inventree)
|
||||
|
||||
*Note: Translation files are updated via GitHub actions - you do not need to compile translations files before submitting a pull request!*
|
||||
|
||||
### Python Code
|
||||
|
||||
For strings exposed via Python code, use the following format:
|
||||
|
||||
```python
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
user_facing_string = _('This string will be exposed to the translation engine!')
|
||||
```
|
||||
|
||||
### Templated Strings
|
||||
|
||||
HTML and javascript files are passed through the django templating engine. Translatable strings are implemented as follows:
|
||||
|
||||
```html
|
||||
{% load i18n %}
|
||||
|
||||
<span>{% trans "This string will be translated" %} - this string will not!</span>
|
||||
```
|
1
InvenTree/InvenTree/locale_stats.json
Normal file
1
InvenTree/InvenTree/locale_stats.json
Normal file
@ -0,0 +1 @@
|
||||
{"de": 95, "el": 0, "en": 0, "es": 4, "fr": 6, "he": 0, "id": 0, "it": 0, "ja": 4, "ko": 0, "nl": 0, "no": 0, "pl": 27, "ru": 6, "sv": 0, "th": 0, "tr": 32, "vi": 0, "zh": 1}
|
@ -8,7 +8,7 @@ import re
|
||||
|
||||
import common.models
|
||||
|
||||
INVENTREE_SW_VERSION = "0.5.0 pre"
|
||||
INVENTREE_SW_VERSION = "0.5.0 dev"
|
||||
|
||||
INVENTREE_API_VERSION = 12
|
||||
|
||||
@ -70,7 +70,7 @@ def inventreeInstanceTitle():
|
||||
|
||||
def inventreeVersion():
|
||||
""" Returns the InvenTree version string """
|
||||
return INVENTREE_SW_VERSION
|
||||
return INVENTREE_SW_VERSION.lower().strip()
|
||||
|
||||
|
||||
def inventreeVersionTuple(version=None):
|
||||
@ -84,6 +84,33 @@ def inventreeVersionTuple(version=None):
|
||||
return [int(g) for g in match.groups()]
|
||||
|
||||
|
||||
def isInvenTreeDevelopmentVersion():
|
||||
"""
|
||||
Return True if current InvenTree version is a "development" version
|
||||
"""
|
||||
|
||||
print("is dev?", inventreeVersion())
|
||||
|
||||
return inventreeVersion().endswith('dev')
|
||||
|
||||
|
||||
def inventreeDocsVersion():
|
||||
"""
|
||||
Return the version string matching the latest documentation.
|
||||
|
||||
Development -> "latest"
|
||||
Release -> "major.minor"
|
||||
|
||||
"""
|
||||
|
||||
if isInvenTreeDevelopmentVersion():
|
||||
return "latest"
|
||||
else:
|
||||
major, minor, patch = inventreeVersionTuple()
|
||||
|
||||
return f"{major}.{minor}"
|
||||
|
||||
|
||||
def isInvenTreeUpToDate():
|
||||
"""
|
||||
Test if the InvenTree instance is "up to date" with the latest version.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -667,6 +667,8 @@
|
||||
});
|
||||
|
||||
onPanelLoad("test-templates", function() {
|
||||
|
||||
// Load test template table
|
||||
loadPartTestTemplateTable(
|
||||
$("#test-template-table"),
|
||||
{
|
||||
@ -677,11 +679,8 @@
|
||||
}
|
||||
);
|
||||
|
||||
// Callback for "add test template" button
|
||||
$("#add-test-template").click(function() {
|
||||
|
||||
function reloadTestTemplateTable() {
|
||||
$("#test-template-table").bootstrapTable("refresh");
|
||||
}
|
||||
|
||||
constructForm('{% url "api-part-test-template-list" %}', {
|
||||
method: 'POST',
|
||||
@ -697,39 +696,10 @@
|
||||
}
|
||||
},
|
||||
title: '{% trans "Add Test Result Template" %}',
|
||||
onSuccess: reloadTestTemplateTable
|
||||
onSuccess: function() {
|
||||
$("#test-template-table").bootstrapTable("refresh");
|
||||
}
|
||||
});
|
||||
|
||||
$("#test-template-table").on('click', '.button-test-edit', function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var url = `/api/part/test-template/${pk}/`;
|
||||
|
||||
constructForm(url, {
|
||||
fields: {
|
||||
test_name: {},
|
||||
description: {},
|
||||
required: {},
|
||||
requires_value: {},
|
||||
requires_attachment: {},
|
||||
},
|
||||
title: '{% trans "Edit Test Result Template" %}',
|
||||
onSuccess: reloadTestTemplateTable,
|
||||
});
|
||||
});
|
||||
|
||||
$("#test-template-table").on('click', '.button-test-delete', function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var url = `/api/part/test-template/${pk}/`;
|
||||
|
||||
constructForm(url, {
|
||||
method: 'DELETE',
|
||||
title: '{% trans "Delete Test Result Template" %}',
|
||||
onSuccess: reloadTestTemplateTable,
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -136,6 +136,21 @@ def inventree_version(*args, **kwargs):
|
||||
return version.inventreeVersion()
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_is_development(*args, **kwargs):
|
||||
return version.isInvenTreeDevelopmentVersion()
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_is_release(*args, **kwargs):
|
||||
return not version.isInvenTreeDevelopmentVersion()
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_docs_version(*args, **kwargs):
|
||||
return version.inventreeDocsVersion()
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def inventree_api_version(*args, **kwargs):
|
||||
""" Return InvenTree API version """
|
||||
@ -169,7 +184,10 @@ def inventree_github_url(*args, **kwargs):
|
||||
@register.simple_tag()
|
||||
def inventree_docs_url(*args, **kwargs):
|
||||
""" Return URL for InvenTree documenation site """
|
||||
return "https://inventree.readthedocs.io/"
|
||||
|
||||
tag = version.inventreeDocsVersion()
|
||||
|
||||
return f"https://inventree.readthedocs.io/en/{tag}"
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
|
@ -22,13 +22,39 @@
|
||||
<td>{% trans "InvenTree Version" %}</td>
|
||||
<td>
|
||||
<a href="https://github.com/inventree/InvenTree/releases">{% inventree_version %}</a>{% include "clip.html" %}
|
||||
{% inventree_is_development as dev %}
|
||||
{% if dev %}
|
||||
<span class='label label-blue float-right'>{% trans "Development Version" %}</span>
|
||||
{% else %}
|
||||
{% if up_to_date %}
|
||||
<span class='label label-green float-right'>{% trans "Up to Date" %}</span>
|
||||
{% else %}
|
||||
<span class='label label-red float-right'>{% trans "Update Available" %}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if dev %}
|
||||
{% inventree_commit_hash as hash %}
|
||||
{% if hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-code-branch'></span></td>
|
||||
<td>{% trans "Commit Hash" %}</td><td>{{ hash }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% inventree_commit_date as commit_date %}
|
||||
{% if commit_date %}
|
||||
<tr>
|
||||
<td><span class='fas fa-calendar-alt'></span></td>
|
||||
<td>{% trans "Commit Date" %}</td><td>{{ commit_date }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td><span class='fas fa-book'></span></td>
|
||||
<td>{% trans "InvenTree Documentation" %}</td>
|
||||
<td><a href="{% inventree_docs_url %}">{% inventree_docs_url %}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-code'></span></td>
|
||||
<td>{% trans "API Version" %}</td>
|
||||
@ -44,25 +70,6 @@
|
||||
<td>{% trans "Django Version" %}</td>
|
||||
<td><a href="https://www.djangoproject.com/">{% django_version %}</a>{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% inventree_commit_hash as hash %}
|
||||
{% if hash %}
|
||||
<tr>
|
||||
<td><span class='fas fa-code-branch'></span></td>
|
||||
<td>{% trans "Commit Hash" %}</td><td>{{ hash }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% inventree_commit_date as commit_date %}
|
||||
{% if commit_date %}
|
||||
<tr>
|
||||
<td><span class='fas fa-calendar-alt'></span></td>
|
||||
<td>{% trans "Commit Date" %}</td><td>{{ commit_date }}{% include "clip.html" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td><span class='fas fa-book'></span></td>
|
||||
<td>{% trans "InvenTree Documentation" %}</td>
|
||||
<td><a href="{% inventree_docs_url %}">{% inventree_docs_url %}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fab fa-github'></span></td>
|
||||
<td>{% trans "View Code on GitHub" %}</td>
|
||||
|
@ -793,14 +793,25 @@ function attachSecondaries(modal, secondaries) {
|
||||
function insertActionButton(modal, options) {
|
||||
/* Insert a custom submission button */
|
||||
|
||||
var html = `
|
||||
<span style='float: right;'>
|
||||
<button name='${options.name}' type='submit' class='btn btn-default modal-form-button' value='${options.name}'>
|
||||
${options.title}
|
||||
</button>
|
||||
</span>`;
|
||||
var element = $(modal).find('#modal-footer-buttons');
|
||||
|
||||
$(modal).find('#modal-footer-buttons').append(html);
|
||||
// check if button already present
|
||||
var already_present = false;
|
||||
for (var child=element[0].firstElementChild; child; child=child.nextElementSibling) {
|
||||
if (item.firstElementChild.name == options.name) {
|
||||
already_present = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (already_present == false) {
|
||||
var html = `
|
||||
<span style='float: right;'>
|
||||
<button name='${options.name}' type='submit' class='btn btn-default modal-form-button' value='${options.name}'>
|
||||
${options.title}
|
||||
</button>
|
||||
</span>`;
|
||||
element.append(html);
|
||||
}
|
||||
}
|
||||
|
||||
function attachButtons(modal, buttons) {
|
||||
|
@ -1252,7 +1252,43 @@ function loadPartTestTemplateTable(table, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
onPostBody: function() {
|
||||
|
||||
table.find('.button-test-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var url = `/api/part/test-template/${pk}/`;
|
||||
|
||||
constructForm(url, {
|
||||
fields: {
|
||||
test_name: {},
|
||||
description: {},
|
||||
required: {},
|
||||
requires_value: {},
|
||||
requires_attachment: {},
|
||||
},
|
||||
title: '{% trans "Edit Test Result Template" %}',
|
||||
onSuccess: function() {
|
||||
table.bootstrapTable('refresh');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
table.find('.button-test-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var url = `/api/part/test-template/${pk}/`;
|
||||
|
||||
constructForm(url, {
|
||||
method: 'DELETE',
|
||||
title: '{% trans "Delete Test Result Template" %}',
|
||||
onSuccess: function() {
|
||||
table.bootstrapTable('refresh');
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,61 @@ if __name__ == '__main__':
|
||||
version = results[0]
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('tag', help='Version tag', action='store')
|
||||
parser.add_argument('-t', '--tag', help='Compare against specified version tag', action='store')
|
||||
parser.add_argument('-r', '--release', help='Check that this is a release version', action='store_true')
|
||||
parser.add_argument('-d', '--dev', help='Check that this is a development version', action='store_true')
|
||||
parser.add_argument('-b', '--branch', help='Check against a particular branch', action='store')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.tag == version:
|
||||
print(f"Release tag '{args.tag}' does not match INVENTREE_SW_VERSION '{version}'")
|
||||
sys.exit(1)
|
||||
if args.branch:
|
||||
"""
|
||||
Version number requirement depends on format of branch
|
||||
|
||||
'master': development branch
|
||||
'stable': release branch
|
||||
"""
|
||||
|
||||
print(f"Checking version number for branch '{args.branch}'")
|
||||
|
||||
if args.branch == 'master':
|
||||
print("- This is a development branch")
|
||||
args.dev = True
|
||||
elif args.branch == 'stable':
|
||||
print("- This is a stable release branch")
|
||||
args.release = True
|
||||
|
||||
if args.dev:
|
||||
"""
|
||||
Check that the current verrsion number matches the "development" format
|
||||
e.g. "0.5 dev"
|
||||
"""
|
||||
|
||||
pattern = "^\d+(\.\d+)+ dev$"
|
||||
|
||||
result = re.match(pattern, version)
|
||||
|
||||
if result is None:
|
||||
print(f"Version number '{version}' does not match required pattern for development branch")
|
||||
sys.exit(1)
|
||||
|
||||
elif args.release:
|
||||
"""
|
||||
Check that the current version number matches the "release" format
|
||||
e.g. "0.5.1"
|
||||
"""
|
||||
|
||||
pattern = "^\d+(\.\d+)+$"
|
||||
|
||||
result = re.match(pattern, version)
|
||||
|
||||
if result is None:
|
||||
print(f"Version number '{version}' does not match required pattern for stable branch")
|
||||
sys.exit(1)
|
||||
|
||||
if args.tag:
|
||||
if not args.tag == version:
|
||||
print(f"Release tag '{args.tag}' does not match INVENTREE_SW_VERSION '{version}'")
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(0)
|
Loading…
Reference in New Issue
Block a user