mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
9c0d060bf2
26
.github/release.yml
vendored
Normal file
26
.github/release.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# .github/release.yml
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
categories:
|
||||||
|
- title: Breaking Changes
|
||||||
|
labels:
|
||||||
|
- Semver-Major
|
||||||
|
- breaking
|
||||||
|
- title: New Features
|
||||||
|
labels:
|
||||||
|
- Semver-Minor
|
||||||
|
- enhancement
|
||||||
|
- title: Bug Fixes
|
||||||
|
labels:
|
||||||
|
- Semver-Patch
|
||||||
|
- bug
|
||||||
|
- title: Devops / Setup Changes
|
||||||
|
labels:
|
||||||
|
- docker
|
||||||
|
- setup
|
||||||
|
- demo
|
||||||
|
- CI
|
||||||
|
- security
|
||||||
|
- title: Other Changes
|
||||||
|
labels:
|
||||||
|
- "*"
|
20
.github/workflows/docker.yaml
vendored
20
.github/workflows/docker.yaml
vendored
@ -2,7 +2,6 @@
|
|||||||
# This workflow runs under any of the following conditions:
|
# This workflow runs under any of the following conditions:
|
||||||
#
|
#
|
||||||
# - Push to the master branch
|
# - Push to the master branch
|
||||||
# - Push to the stable branch
|
|
||||||
# - Publish release
|
# - Publish release
|
||||||
#
|
#
|
||||||
# The following actions are performed:
|
# The following actions are performed:
|
||||||
@ -21,7 +20,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'stable'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@ -29,12 +27,15 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repo
|
- name: Check out repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Version Check
|
- name: Version Check
|
||||||
run: |
|
run: |
|
||||||
python3 ci/check_version_number.py
|
python3 ci/version_check.py
|
||||||
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
||||||
- name: Run Unit Tests
|
- name: Run Unit Tests
|
||||||
@ -65,5 +66,14 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||||
push: true
|
push: true
|
||||||
target: production
|
target: production
|
||||||
tags: inventree/inventree:${{ env.docker_tag }}
|
tags: ${{ env.docker_tags }}
|
||||||
build-args: commit_hash=${{ env.git_commit_hash }},commit_date=${{ env.git_commit_date }},commit_tag=${{ env.docker_tag }}
|
build-args: |
|
||||||
|
commit_hash=${{ env.git_commit_hash }}
|
||||||
|
commit_date=${{ env.git_commit_date }}
|
||||||
|
- name: Push to Stable Branch
|
||||||
|
uses: ad-m/github-push-action@master
|
||||||
|
if: env.stable_release == 'true'
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: stable
|
||||||
|
force: true
|
||||||
|
3
.github/workflows/qc_checks.yaml
vendored
3
.github/workflows/qc_checks.yaml
vendored
@ -91,9 +91,6 @@ jobs:
|
|||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Run pre-commit Checks
|
- name: Run pre-commit Checks
|
||||||
uses: pre-commit/action@v2.0.3
|
uses: pre-commit/action@v2.0.3
|
||||||
- name: Check version number
|
|
||||||
run: |
|
|
||||||
python3 ci/check_version_number.py
|
|
||||||
|
|
||||||
python:
|
python:
|
||||||
name: Tests - inventree-python
|
name: Tests - inventree-python
|
||||||
|
@ -137,6 +137,7 @@ The tags describe issues and PRs in multiple areas:
|
|||||||
| Area | Name | Description |
|
| Area | Name | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Type Labels | | |
|
| Type Labels | | |
|
||||||
|
| | breaking | Indicates a major update or change which breaks compatibility |
|
||||||
| | bug | Identifies a bug which needs to be addressed |
|
| | bug | Identifies a bug which needs to be addressed |
|
||||||
| | dependency | Relates to a project dependency |
|
| | dependency | Relates to a project dependency |
|
||||||
| | duplicate | Duplicate of another issue or PR |
|
| | duplicate | Duplicate of another issue or PR |
|
||||||
|
@ -105,10 +105,9 @@ COPY docker/init.sh ${INVENTREE_MNG_DIR}/init.sh
|
|||||||
WORKDIR ${INVENTREE_MNG_DIR}
|
WORKDIR ${INVENTREE_MNG_DIR}
|
||||||
|
|
||||||
# Drop to the inventree user for the production image
|
# Drop to the inventree user for the production image
|
||||||
RUN adduser inventree
|
#RUN adduser inventree
|
||||||
RUN chown -R inventree:inventree ${INVENTREE_HOME}
|
#RUN chown -R inventree:inventree ${INVENTREE_HOME}
|
||||||
|
#USER inventree
|
||||||
USER inventree
|
|
||||||
|
|
||||||
# Install InvenTree packages
|
# Install InvenTree packages
|
||||||
RUN pip3 install --user --disable-pip-version-check -r ${INVENTREE_HOME}/requirements.txt
|
RUN pip3 install --user --disable-pip-version-check -r ${INVENTREE_HOME}/requirements.txt
|
||||||
|
@ -4,11 +4,17 @@ InvenTree API version information
|
|||||||
|
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 51
|
INVENTREE_API_VERSION = 53
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||||
|
|
||||||
|
v52 -> 2022-06-01 : https://github.com/inventree/InvenTree/pull/3110
|
||||||
|
- Adds extra search fields to the BuildOrder list API endpoint
|
||||||
|
|
||||||
|
v52 -> 2022-05-31 : https://github.com/inventree/InvenTree/pull/3103
|
||||||
|
- Allow part list API to be searched by supplier SKU
|
||||||
|
|
||||||
v51 -> 2022-05-24 : https://github.com/inventree/InvenTree/pull/3058
|
v51 -> 2022-05-24 : https://github.com/inventree/InvenTree/pull/3058
|
||||||
- Adds new fields to the SalesOrderShipment model
|
- Adds new fields to the SalesOrderShipment model
|
||||||
|
|
||||||
|
@ -106,8 +106,10 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
|
|||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
'reference',
|
'reference',
|
||||||
'part__name',
|
|
||||||
'title',
|
'title',
|
||||||
|
'part__name',
|
||||||
|
'part__IPN',
|
||||||
|
'part__description',
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -375,7 +375,7 @@ onPanelLoad('attachments', function() {
|
|||||||
},
|
},
|
||||||
label: 'attachment',
|
label: 'attachment',
|
||||||
success: function(data, status, xhr) {
|
success: function(data, status, xhr) {
|
||||||
location.reload();
|
$('#attachment-table').bootstrapTable('refresh');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.utils import IntegrityError
|
|
||||||
|
|
||||||
from InvenTree import status_codes as status
|
from InvenTree import status_codes as status
|
||||||
|
|
||||||
@ -194,14 +193,13 @@ class BuildTest(BuildTestBase):
|
|||||||
b.save()
|
b.save()
|
||||||
|
|
||||||
def test_duplicate_bom_line(self):
|
def test_duplicate_bom_line(self):
|
||||||
# Try to add a duplicate BOM item - it should fail!
|
# Try to add a duplicate BOM item - it should be allowed
|
||||||
|
|
||||||
with self.assertRaises(IntegrityError):
|
BomItem.objects.create(
|
||||||
BomItem.objects.create(
|
part=self.assembly,
|
||||||
part=self.assembly,
|
sub_part=self.sub_part_1,
|
||||||
sub_part=self.sub_part_1,
|
quantity=99
|
||||||
quantity=99
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def allocate_stock(self, output, allocations):
|
def allocate_stock(self, output, allocations):
|
||||||
"""
|
"""
|
||||||
|
@ -1425,6 +1425,20 @@ class InvenTreeUserSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_SUPPLIER_PARTS': {
|
||||||
|
'name': _('Seach Supplier Parts'),
|
||||||
|
'description': _('Display supplier parts in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
|
'SEARCH_PREVIEW_SHOW_MANUFACTURER_PARTS': {
|
||||||
|
'name': _('Search Manufacturer Parts'),
|
||||||
|
'description': _('Display manufacturer parts in search preview window'),
|
||||||
|
'default': True,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
|
|
||||||
'SEARCH_HIDE_INACTIVE_PARTS': {
|
'SEARCH_HIDE_INACTIVE_PARTS': {
|
||||||
'name': _("Hide Inactive Parts"),
|
'name': _("Hide Inactive Parts"),
|
||||||
'description': _('Excluded inactive parts from search preview window'),
|
'description': _('Excluded inactive parts from search preview window'),
|
||||||
|
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
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
@ -1387,6 +1387,7 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
|||||||
'keywords',
|
'keywords',
|
||||||
'category__name',
|
'category__name',
|
||||||
'manufacturer_parts__MPN',
|
'manufacturer_parts__MPN',
|
||||||
|
'supplier_parts__SKU',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-05-31 01:42
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('part', '0076_auto_20220516_0819'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='bomitem',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
]
|
@ -2899,9 +2899,6 @@ class BomItem(models.Model, DataImportMixin):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("BOM Item")
|
verbose_name = _("BOM Item")
|
||||||
|
|
||||||
# Prevent duplication of parent/child rows
|
|
||||||
unique_together = ('part', 'sub_part')
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{n} x {child} to make {parent}".format(
|
return "{n} x {child} to make {parent}".format(
|
||||||
parent=self.part.full_name,
|
parent=self.part.full_name,
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_PARTS" user_setting=True icon='fa-shapes' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_PARTS" user_setting=True icon='fa-shapes' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_HIDE_INACTIVE_PARTS" user_setting=True icon='fa-eye-slash' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_HIDE_INACTIVE_PARTS" user_setting=True icon='fa-eye-slash' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_SUPPLIER_PARTS" user_setting=True icon='fa-building' %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_MANUFACTURER_PARTS" user_setting=True icon='fa-industry' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_CATEGORIES" user_setting=True icon='fa-sitemap' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_CATEGORIES" user_setting=True icon='fa-sitemap' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_STOCK" user_setting=True icon='fa-boxes' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_SHOW_STOCK" user_setting=True icon='fa-boxes' %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_HIDE_UNAVAILABLE_STOCK" user_setting=True icon='fa-eye-slash' %}
|
{% include "InvenTree/settings/setting.html" with key="SEARCH_PREVIEW_HIDE_UNAVAILABLE_STOCK" user_setting=True icon='fa-eye-slash' %}
|
||||||
|
@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
<div id='attachment-buttons'>
|
<div id='attachment-buttons'>
|
||||||
<div class='btn-group' role='group'>
|
<div class='btn-group' role='group'>
|
||||||
|
<div class='btn-group'>
|
||||||
|
<button class='btn btn-primary dropdown-toggle' type='buton' data-bs-toggle='dropdown' title='{% trans "Actions" %}'>
|
||||||
|
<span class='fas fa-tools'></span> <span class='caret'></span>
|
||||||
|
</button>
|
||||||
|
<ul class='dropdown-menu'>
|
||||||
|
<li>
|
||||||
|
<a class='dropdown-item' href='#' id='multi-attachment-delete' title='{% trans "Delete selected attachments" %}'>
|
||||||
|
<span class='fas fa-trash-alt icon-red'></span> {% trans "Delete Attachments" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
{% include "filter_list.html" with id="attachments" %}
|
{% include "filter_list.html" with id="attachments" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,6 +57,75 @@ function addAttachmentButtonCallbacks(url, fields={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct a form to delete attachment files
|
||||||
|
*/
|
||||||
|
function deleteAttachments(attachments, url, options={}) {
|
||||||
|
|
||||||
|
if (attachments.length == 0) {
|
||||||
|
console.warn('deleteAttachments function called with zero attachments provided');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderAttachment(attachment, opts={}) {
|
||||||
|
|
||||||
|
var icon = '';
|
||||||
|
|
||||||
|
if (attachment.filename) {
|
||||||
|
icon = `<span class='fas fa-file-alt'></span>`;
|
||||||
|
} else if (attachment.link) {
|
||||||
|
icon = `<span class='fas fa-link'></span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<tr>
|
||||||
|
<td>${icon}</td>
|
||||||
|
<td>${attachment.filename || attachment.link}</td>
|
||||||
|
<td>${attachment.comment}</td>
|
||||||
|
</tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = '';
|
||||||
|
|
||||||
|
attachments.forEach(function(att) {
|
||||||
|
rows += renderAttachment(att);
|
||||||
|
});
|
||||||
|
|
||||||
|
var html = `
|
||||||
|
<div class='alert alert-block alert-danger'>
|
||||||
|
{% trans "All selected attachments will be deleted" %}
|
||||||
|
</div>
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>{% trans "Attachment" %}</th>
|
||||||
|
<th>{% trans "Comment" %}</th>
|
||||||
|
</tr>
|
||||||
|
${rows}
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
|
||||||
|
constructFormBody({}, {
|
||||||
|
method: 'DELETE',
|
||||||
|
title: '{% trans "Delete Attachments" %}',
|
||||||
|
preFormContent: html,
|
||||||
|
onSubmit: function(fields, opts) {
|
||||||
|
inventreeMultiDelete(
|
||||||
|
url,
|
||||||
|
attachments,
|
||||||
|
{
|
||||||
|
modal: opts.modal,
|
||||||
|
success: function() {
|
||||||
|
// Refresh the table once all attachments are deleted
|
||||||
|
$('#attachment-table').bootstrapTable('refresh');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function reloadAttachmentTable() {
|
function reloadAttachmentTable() {
|
||||||
|
|
||||||
$('#attachment-table').bootstrapTable('refresh');
|
$('#attachment-table').bootstrapTable('refresh');
|
||||||
@ -71,6 +140,15 @@ function loadAttachmentTable(url, options) {
|
|||||||
|
|
||||||
addAttachmentButtonCallbacks(url, options.fields || {});
|
addAttachmentButtonCallbacks(url, options.fields || {});
|
||||||
|
|
||||||
|
// Add callback for the 'multi delete' button
|
||||||
|
$('#multi-attachment-delete').click(function() {
|
||||||
|
var attachments = getTableData(table);
|
||||||
|
|
||||||
|
if (attachments.length > 0) {
|
||||||
|
deleteAttachments(attachments, url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$(table).inventreeTable({
|
$(table).inventreeTable({
|
||||||
url: url,
|
url: url,
|
||||||
name: options.name || 'attachments',
|
name: options.name || 'attachments',
|
||||||
@ -80,7 +158,9 @@ function loadAttachmentTable(url, options) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
queryParams: options.filters || {},
|
queryParams: options.filters || {},
|
||||||
|
uniqueId: 'pk',
|
||||||
onPostBody: function() {
|
onPostBody: function() {
|
||||||
|
|
||||||
// Add callback for 'edit' button
|
// Add callback for 'edit' button
|
||||||
$(table).find('.button-attachment-edit').click(function() {
|
$(table).find('.button-attachment-edit').click(function() {
|
||||||
var pk = $(this).attr('pk');
|
var pk = $(this).attr('pk');
|
||||||
@ -105,15 +185,14 @@ function loadAttachmentTable(url, options) {
|
|||||||
$(table).find('.button-attachment-delete').click(function() {
|
$(table).find('.button-attachment-delete').click(function() {
|
||||||
var pk = $(this).attr('pk');
|
var pk = $(this).attr('pk');
|
||||||
|
|
||||||
constructForm(`${url}${pk}/`, {
|
var attachment = $(table).bootstrapTable('getRowByUniqueId', pk);
|
||||||
method: 'DELETE',
|
deleteAttachments([attachment], url);
|
||||||
confirmMessage: '{% trans "Confirm Delete" %}',
|
|
||||||
title: '{% trans "Delete Attachment" %}',
|
|
||||||
onSuccess: reloadAttachmentTable,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
|
{
|
||||||
|
checkbox: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'attachment',
|
field: 'attachment',
|
||||||
title: '{% trans "Attachment" %}',
|
title: '{% trans "Attachment" %}',
|
||||||
|
@ -151,6 +151,46 @@ function updateSearch() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkPermission('part') && checkPermission('purchase_order')) {
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
part_detail: true,
|
||||||
|
supplier_detail: true,
|
||||||
|
manufacturer_detail: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_HIDE_INACTIVE_PARTS) {
|
||||||
|
// Return *only* active parts
|
||||||
|
params.active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_SUPPLIER_PARTS) {
|
||||||
|
addSearchQuery(
|
||||||
|
'supplierpart',
|
||||||
|
'{% trans "Supplier Parts" %}',
|
||||||
|
'{% url "api-supplier-part-list" %}',
|
||||||
|
params,
|
||||||
|
renderSupplierPart,
|
||||||
|
{
|
||||||
|
url: '/supplier-part',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings.SEARCH_PREVIEW_SHOW_MANUFACTURER_PARTS) {
|
||||||
|
addSearchQuery(
|
||||||
|
'manufacturerpart',
|
||||||
|
'{% trans "Manufacturer Parts" %}',
|
||||||
|
'{% url "api-manufacturer-part-list" %}',
|
||||||
|
params,
|
||||||
|
renderManufacturerPart,
|
||||||
|
{
|
||||||
|
url: '/manufacturer-part',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (checkPermission('part_category') && user_settings.SEARCH_PREVIEW_SHOW_CATEGORIES) {
|
if (checkPermission('part_category') && user_settings.SEARCH_PREVIEW_SHOW_CATEGORIES) {
|
||||||
// Search for matching part categories
|
// Search for matching part categories
|
||||||
addSearchQuery(
|
addSearchQuery(
|
||||||
|
@ -4,20 +4,79 @@ Ensure that the release tag matches the InvenTree version number:
|
|||||||
master / main branch:
|
master / main branch:
|
||||||
- version number must end with 'dev'
|
- version number must end with 'dev'
|
||||||
|
|
||||||
stable branch:
|
|
||||||
- version number must *not* end with 'dev'
|
|
||||||
- version number cannot already exist as a release tag
|
|
||||||
|
|
||||||
tagged branch:
|
tagged branch:
|
||||||
- version number must match tag being built
|
- version number must match tag being built
|
||||||
- version number cannot already exist as a release tag
|
- version number cannot already exist as a release tag
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def get_existing_release_tags():
|
||||||
|
"""Request information on existing releases via the GitHub API"""
|
||||||
|
|
||||||
|
response = requests.get('https://api.github.com/repos/inventree/inventree/releases')
|
||||||
|
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise ValueError(f'Unexpected status code from GitHub API: {response.status_code}')
|
||||||
|
|
||||||
|
data = json.loads(response.text)
|
||||||
|
|
||||||
|
# Return a list of all tags
|
||||||
|
tags = []
|
||||||
|
|
||||||
|
for release in data:
|
||||||
|
tag = release['tag_name'].strip()
|
||||||
|
match = re.match(r"^.*(\d+)\.(\d+)\.(\d+).*$", tag)
|
||||||
|
|
||||||
|
if len(match.groups()) != 3:
|
||||||
|
print(f"Version '{tag}' did not match expected pattern")
|
||||||
|
continue
|
||||||
|
|
||||||
|
tags.append([int(x) for x in match.groups()])
|
||||||
|
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def check_version_number(version_string):
|
||||||
|
"""Check the provided version number.
|
||||||
|
|
||||||
|
Returns True if the provided version is the 'newest' InvenTree release
|
||||||
|
"""
|
||||||
|
|
||||||
|
print(f"Checking version '{version_string}'")
|
||||||
|
|
||||||
|
# Check that the version string matches the required format
|
||||||
|
match = re.match(r"^(\d+)\.(\d+)\.(\d+)(?: dev)?$", version_string)
|
||||||
|
|
||||||
|
if not match or len(match.groups()) != 3:
|
||||||
|
raise ValueError(f"Version string '{version_string}' did not match required pattern")
|
||||||
|
|
||||||
|
version_tuple = [int(x) for x in match.groups()]
|
||||||
|
|
||||||
|
# Look through the existing releases
|
||||||
|
existing = get_existing_release_tags()
|
||||||
|
|
||||||
|
# Assume that this is the highest release, unless told otherwise
|
||||||
|
highest_release = True
|
||||||
|
|
||||||
|
for release in existing:
|
||||||
|
if release == version_tuple:
|
||||||
|
raise ValueError(f"Duplicate release '{version_string}' exists!")
|
||||||
|
|
||||||
|
if release > version_tuple:
|
||||||
|
highest_release = False
|
||||||
|
print(f"Found newer release: {str(release)}")
|
||||||
|
|
||||||
|
return highest_release
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
here = os.path.abspath(os.path.dirname(__file__))
|
here = os.path.abspath(os.path.dirname(__file__))
|
||||||
@ -49,24 +108,12 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
print(f"InvenTree Version: '{version}'")
|
print(f"InvenTree Version: '{version}'")
|
||||||
|
|
||||||
|
highest_release = check_version_number(version)
|
||||||
|
|
||||||
# Determine which docker tag we are going to use
|
# Determine which docker tag we are going to use
|
||||||
docker_tag = None
|
docker_tags = None
|
||||||
|
|
||||||
if GITHUB_REF_TYPE == 'branch' and ('stable' in GITHUB_REF or 'stable' in GITHUB_BASE_REF):
|
if GITHUB_REF_TYPE == 'tag':
|
||||||
print("Checking requirements for 'stable' release branch:")
|
|
||||||
|
|
||||||
pattern = r"^\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)
|
|
||||||
else:
|
|
||||||
print(f"Version number '{version}' matches stable branch")
|
|
||||||
|
|
||||||
docker_tag = 'stable'
|
|
||||||
|
|
||||||
elif GITHUB_REF_TYPE == 'tag':
|
|
||||||
# GITHUB_REF should be of th eform /refs/heads/<tag>
|
# GITHUB_REF should be of th eform /refs/heads/<tag>
|
||||||
version_tag = GITHUB_REF.split('/')[-1]
|
version_tag = GITHUB_REF.split('/')[-1]
|
||||||
print(f"Checking requirements for tagged release - '{version_tag}':")
|
print(f"Checking requirements for tagged release - '{version_tag}':")
|
||||||
@ -77,7 +124,10 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# TODO: Check if there is already a release with this tag!
|
# TODO: Check if there is already a release with this tag!
|
||||||
|
|
||||||
docker_tag = version_tag
|
if highest_release:
|
||||||
|
docker_tags = [version_tag, 'stable']
|
||||||
|
else:
|
||||||
|
docker_tags = [version_tag]
|
||||||
|
|
||||||
elif GITHUB_REF_TYPE == 'branch':
|
elif GITHUB_REF_TYPE == 'branch':
|
||||||
# Otherwise we know we are targetting the 'master' branch
|
# Otherwise we know we are targetting the 'master' branch
|
||||||
@ -92,7 +142,7 @@ if __name__ == '__main__':
|
|||||||
else:
|
else:
|
||||||
print(f"Version number '{version}' matches development branch")
|
print(f"Version number '{version}' matches development branch")
|
||||||
|
|
||||||
docker_tag = 'latest'
|
docker_tags = ['latest']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("Unsupported branch / version combination:")
|
print("Unsupported branch / version combination:")
|
||||||
@ -102,13 +152,20 @@ if __name__ == '__main__':
|
|||||||
print("GITHUB_REF:", GITHUB_REF)
|
print("GITHUB_REF:", GITHUB_REF)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if docker_tag is None:
|
if docker_tags is None:
|
||||||
print("Docker tag could not be determined")
|
print("Docker tag could not be determined")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print(f"Version check passed for '{version}'!")
|
print(f"Version check passed for '{version}'!")
|
||||||
print(f"Docker tag: '{docker_tag}'")
|
print(f"Docker tags: '{docker_tags}'")
|
||||||
|
|
||||||
# Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/
|
# Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/
|
||||||
with open(os.getenv('GITHUB_ENV'), 'a') as env_file:
|
with open(os.getenv('GITHUB_ENV'), 'a') as env_file:
|
||||||
env_file.write(f"docker_tag={docker_tag}\n")
|
|
||||||
|
# Construct tag string
|
||||||
|
tags = ",".join([f"inventree/inventree:{tag}" for tag in docker_tags])
|
||||||
|
|
||||||
|
env_file.write(f"docker_tags={tags}\n")
|
||||||
|
|
||||||
|
if GITHUB_REF_TYPE == 'tag' and highest_release:
|
||||||
|
env_file.write("stable_release=true\n")
|
Loading…
Reference in New Issue
Block a user