mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
* Run every profile maintenance job from one tool orca_id_tool.py becomes orca_profile_tool.py, and orca_extra_profile_check.py and orca_filament_lib.py fold into it as subcommands: check, generate-id, fix, trim, update-index and update-snapshot. The three scripts already overlapped -- the checker imported half of its rules from the id tool, which in turn kept a copy-pasted set of output helpers to avoid the resulting import cycle -- while disagreeing on how a vendor is enumerated, how a JSON file is read and what the exit code means. One file settles all three. check, normalize, trim and update-index reproduce their predecessors exactly; normalize and update-index were diffed byte-for-byte against the old scripts over a copy of the whole tree. Deliberate changes: the compatible-printers check no longer switches itself off when --check-materials is passed, an error exits 1 rather than -1, update-index honours --profile-type and reports a profile it cannot place instead of dropping it from the index, fix and update-index gained --dry-run, trim keeps an unindexed file some surviving profile still inherits from, and vendors are enumerated as directories with an index -- which is why blacklist.json, a data file that an unscoped index rebuild once wrote four empty list sections into, loses them here and will not collect them again. The dead rename_filament_system() helper is gone. The suite under scripts/tests now covers the maintenance commands too, and CI runs it; nothing there ran in CI before. No shipped profile data changes apart from those four keys. * update vendor index files with "python3 ./scripts/orca_profile_tool.py update-index" and "python3 ./scripts/orca_profile_tool.py normalize"
272 lines
11 KiB
YAML
272 lines
11 KiB
YAML
name: Check profiles
|
|
on:
|
|
pull_request:
|
|
# release/* is included because pr-merge-bot.yml lets delegates merge into
|
|
# it, and it gates on this workflow's result. Without it a delegated merge
|
|
# into a release branch would run no profile validation at all.
|
|
branches:
|
|
- main
|
|
- release/*
|
|
paths:
|
|
- 'resources/profiles/**'
|
|
# orca_profile_tool.py also validates resources/printers/bambu_filament_ids.json, and
|
|
# both it and its tests live in scripts/, so a PR touching only those must still run
|
|
# this workflow.
|
|
- 'resources/printers/**'
|
|
- 'scripts/**'
|
|
- ".github/workflows/check_profiles.yml"
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
logLevel:
|
|
description: 'Log level'
|
|
required: true
|
|
default: 'warning'
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
|
|
jobs:
|
|
check_profiles:
|
|
# This job name is the check-run name pr-merge-bot.yml requires before a
|
|
# delegated merge. Renaming it silently disables that gate.
|
|
name: Check profiles
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v7
|
|
|
|
# Deliberately not continue-on-error, unlike every check below: if the tool itself is
|
|
# broken, nothing it then reports about the profiles is worth reading.
|
|
- name: Run the profile tool's own unit tests
|
|
run: python3 -m unittest discover -s scripts/tests -t scripts
|
|
|
|
# What the validator below cannot see. It loads the tree the way the slicer does, so
|
|
# it never notices a profile no <vendor>.json indexes, a preset name two files claim,
|
|
# an id that is not the mint of its own triple, or a file that normalize and
|
|
# update-index would still rewrite.
|
|
# The step id is the handle the PR comment and the failure gate below use; renaming it
|
|
# silently disables them.
|
|
- name: Check profiles (orca_profile_tool.py)
|
|
id: profile_tool
|
|
continue-on-error: true
|
|
run: |
|
|
set +e
|
|
python3 ./scripts/orca_profile_tool.py check 2>&1 | tee ${{ runner.temp }}/profile_tool.log
|
|
exit ${PIPESTATUS[0]}
|
|
|
|
# download
|
|
- name: Download
|
|
working-directory: ${{ github.workspace }}
|
|
run: |
|
|
curl -L -o OrcaSlicer_profile_validator https://github.com/OrcaSlicer/OrcaSlicer/releases/download/nightly-builds/OrcaSlicer_profile_validator_Linux_Ubuntu2404_nightly
|
|
chmod +x ./OrcaSlicer_profile_validator
|
|
|
|
# Validate all system profiles.
|
|
- name: validate system profiles
|
|
id: validate_system
|
|
continue-on-error: true
|
|
run: |
|
|
set +e
|
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 2>&1 | tee ${{ runner.temp }}/validate_system.log
|
|
exit ${PIPESTATUS[0]}
|
|
# Slice a two-colour cube through every printer so all custom g-code (incl. change_filament_gcode)
|
|
# is expanded - catches undefined-placeholder / invalid-flow bugs the static checks above cannot see.
|
|
- name: validate slice (expand custom g-code)
|
|
id: validate_slice
|
|
continue-on-error: true
|
|
run: |
|
|
set +e
|
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
|
|
exit ${PIPESTATUS[0]}
|
|
# All vendors' filament_id collisions were fixed (see scripts/filament_id_snapshot.json),
|
|
# so the duplicate-filament-subtype check runs tree-wide.
|
|
- name: validate filament subtype check
|
|
id: validate_filament_subtypes
|
|
continue-on-error: true
|
|
run: |
|
|
set +e
|
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
|
exit ${PIPESTATUS[0]}
|
|
|
|
- name: validate custom presets
|
|
id: validate_custom
|
|
continue-on-error: true
|
|
working-directory: ${{ github.workspace }}
|
|
run: |
|
|
fixtures_dir="${{ runner.temp }}/profile-fixtures"
|
|
output_dir="${{ runner.temp }}/custom-preset-validation"
|
|
combined_log="${{ runner.temp }}/validate_custom.log"
|
|
summary="${output_dir}/summary.md"
|
|
release_url="https://github.com/OrcaSlicer/OrcaSlicer-profile-validator/releases/download/fixture-archive"
|
|
|
|
rm -rf "${fixtures_dir}" "${output_dir}"
|
|
mkdir -p "${fixtures_dir}" "${output_dir}"
|
|
|
|
curl -fsSL -o "${fixtures_dir}/manifest.json" "${release_url}/manifest.json"
|
|
|
|
MANIFEST_PATH="${fixtures_dir}/manifest.json" python3 <<'PY' > "${fixtures_dir}/fixtures.tsv"
|
|
import json
|
|
import os
|
|
|
|
with open(os.environ["MANIFEST_PATH"], encoding="utf-8") as fh:
|
|
manifest = json.load(fh)
|
|
|
|
if isinstance(manifest, dict):
|
|
entries = manifest.get("fixtures", [])
|
|
else:
|
|
entries = manifest
|
|
|
|
for entry in entries:
|
|
version = entry.get("version", "")
|
|
asset = entry.get("asset", "")
|
|
sha256 = entry.get("asset_sha256", "")
|
|
if not version or not asset:
|
|
continue
|
|
print(f"{version}\t{asset}\t{sha256}")
|
|
PY
|
|
|
|
if [ ! -s "${fixtures_dir}/fixtures.tsv" ]; then
|
|
echo "No custom preset fixtures found in ${release_url}/manifest.json" | tee "${combined_log}"
|
|
exit 1
|
|
fi
|
|
|
|
{
|
|
echo "## Custom Preset Fixture Validation"
|
|
echo ""
|
|
echo "| Version | Status | Log |"
|
|
echo "| --- | --- | --- |"
|
|
} > "${summary}"
|
|
|
|
status=0
|
|
failed_logs=()
|
|
|
|
while IFS=$'\t' read -r version asset expected_sha256; do
|
|
fixture_zip="${fixtures_dir}/${asset}"
|
|
asset_url_name="$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "${asset}")"
|
|
profile_tree="${output_dir}/profiles-${version}"
|
|
log_path="${output_dir}/${version}.log"
|
|
|
|
curl -fsSL -o "${fixture_zip}" "${release_url}/${asset_url_name}"
|
|
|
|
if [ -n "${expected_sha256}" ] && [ "${expected_sha256}" != "<sha256>" ]; then
|
|
echo "${expected_sha256} ${fixture_zip}" | sha256sum -c -
|
|
fi
|
|
|
|
rm -rf "${profile_tree}"
|
|
mkdir -p "${profile_tree}"
|
|
cp -a "${{ github.workspace }}/resources/profiles/." "${profile_tree}/"
|
|
rm -rf "${profile_tree}/user"
|
|
unzip -q "${fixture_zip}" -d "${profile_tree}"
|
|
|
|
set +e
|
|
./OrcaSlicer_profile_validator -p "${profile_tree}" -l 2 > "${log_path}" 2>&1
|
|
result=$?
|
|
set -e
|
|
|
|
if [ "${result}" -eq 0 ]; then
|
|
echo "| ${version} | PASS | ${version}.log |" >> "${summary}"
|
|
else
|
|
echo "| ${version} | FAIL | ${version}.log |" >> "${summary}"
|
|
failed_logs+=("${log_path}")
|
|
status=1
|
|
fi
|
|
done < "${fixtures_dir}/fixtures.tsv"
|
|
|
|
{
|
|
cat "${summary}"
|
|
if [ "${#failed_logs[@]}" -gt 0 ]; then
|
|
echo ""
|
|
echo "## Failed Fixture Logs"
|
|
for log_path in "${failed_logs[@]}"; do
|
|
echo ""
|
|
echo "### $(basename "${log_path}" .log)"
|
|
echo '```'
|
|
head -c 12000 "${log_path}" || echo "No output captured"
|
|
echo '```'
|
|
done
|
|
fi
|
|
} | tee "${combined_log}"
|
|
|
|
exit "${status}"
|
|
|
|
- name: Prepare PR number for comment workflow
|
|
if: ${{ always() && github.event_name == 'pull_request' }}
|
|
run: |
|
|
mkdir -p ${{ runner.temp }}/profile-check-results
|
|
echo "${{ github.event.pull_request.number }}" > ${{ runner.temp }}/profile-check-results/pr_number.txt
|
|
|
|
- name: Prepare comment artifact
|
|
if: ${{ always() && github.event_name == 'pull_request' && (steps.profile_tool.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
|
run: |
|
|
{
|
|
# Marker matched by check_profiles_comment.yml to delete prior comments.
|
|
echo "<!-- profile-validation-comment -->"
|
|
echo "## :x: Profile Validation Errors"
|
|
echo ""
|
|
|
|
if [ "${{ steps.profile_tool.outcome }}" = "failure" ]; then
|
|
echo "### Profile Check Failed (orca_profile_tool.py)"
|
|
echo ""
|
|
echo '```'
|
|
head -c 30000 ${{ runner.temp }}/profile_tool.log || echo "No output captured"
|
|
echo '```'
|
|
echo ""
|
|
fi
|
|
|
|
if [ "${{ steps.validate_system.outcome }}" = "failure" ]; then
|
|
echo "### System Profile Validation Failed"
|
|
echo ""
|
|
echo '```'
|
|
head -c 30000 ${{ runner.temp }}/validate_system.log || echo "No output captured"
|
|
echo '```'
|
|
echo ""
|
|
fi
|
|
|
|
if [ "${{ steps.validate_slice.outcome }}" = "failure" ]; then
|
|
echo "### Slice Validation Failed (custom g-code expansion)"
|
|
echo ""
|
|
echo '```'
|
|
head -c 30000 ${{ runner.temp }}/validate_slice.log || echo "No output captured"
|
|
echo '```'
|
|
echo ""
|
|
fi
|
|
|
|
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
|
echo "### Filament Subtype Validation Failed"
|
|
echo ""
|
|
echo '```'
|
|
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"
|
|
echo '```'
|
|
echo ""
|
|
fi
|
|
|
|
if [ "${{ steps.validate_custom.outcome }}" = "failure" ]; then
|
|
echo "### Custom Preset Validation Failed"
|
|
echo ""
|
|
echo '```'
|
|
head -c 30000 ${{ runner.temp }}/validate_custom.log || echo "No output captured"
|
|
echo '```'
|
|
echo ""
|
|
fi
|
|
|
|
echo "---"
|
|
echo '*Fix the errors above and push a new commit. To reproduce this run locally: `scripts/check_profile.sh`, or `scripts\check_profile.bat` on Windows.*'
|
|
} > ${{ runner.temp }}/profile-check-results/pr_comment.md
|
|
|
|
- name: Upload comment artifact
|
|
if: ${{ always() && github.event_name == 'pull_request' }}
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: profile-check-results
|
|
path: ${{ runner.temp }}/profile-check-results/
|
|
retention-days: 1
|
|
|
|
- name: Fail if any check failed
|
|
if: ${{ always() && (steps.profile_tool.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_slice.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
|
run: |
|
|
echo "One or more profile checks failed; see the step logs above."
|
|
echo 'Reproduce the whole run locally with scripts/check_profile.sh (scripts\check_profile.bat on Windows).'
|
|
exit 1
|