Upgrade to py-allspice 3.0.0

This commit is contained in:
Jonathan Tran 2024-05-10 11:56:24 -04:00
parent 9cf4d5313c
commit 69597ea009
4 changed files with 73 additions and 61 deletions

View File

@ -2,6 +2,6 @@ FROM python:3.12-bookworm
COPY entrypoint.py /entrypoint.py
RUN pip install py-allspice~=2.5
RUN pip install py-allspice~=3.0
ENTRYPOINT [ "/entrypoint.py" ]

View File

@ -1,25 +1,33 @@
# Generate BOM for Altium Projects
Generate a BOM for an Altium project on AllSpice Hub using py-allspice. This
currently uses the PCB file for computing quantities.
Generate a BOM for an Altium project on AllSpice Hub using py-allspice.
## Usage
Add the following step to your actions:
Add the following steps to your actions:
```yaml
# Checkout is only needed if columns.json is committed in the repo.
- name: Checkout
uses: actions/checkout@v3
- name: Generate BOM
uses: https://hub.allspice.io/Actions/generate-bom-altium@main
with:
project_path: Archimajor.PrjPcb
pcb_path: Archimajor.PcbDoc
columns: columns.json
output_file_name: bom.csv
attributes_mapping: '
{
"description": ["PART DESCRIPTION"],
"designator": ["Designator"],
"manufacturer": ["Manufacturer", "MANUFACTURER"],
"part_number": ["PART", "MANUFACTURER #"]
}
'
```
where `columns.json` looks like:
```json
{
"part_number": ["PART", "MANUFACTURER #", "MPN"],
"manufacturer": ["Manufacturer", "MANUFACTURER", "MFG", "Mfg"],
"designator": ["Designator", "REFDES", "Refdes", "Ref"],
"part_id": ["_part_id"],
"description": ["PART DESCRIPTION", "_description"]
}
```

View File

@ -7,16 +7,19 @@ inputs:
project_path:
description: "Path to the project file from the root of the repo"
required: true
pcb_path:
description: "Path to the PCB file from the root of the repo"
required: true
output_file_name:
description: "Name of the output file"
required: true
default: "bom.csv"
attributes_mapping:
description: "JSON string with the mapping of the attributes to the AllSpice attributes"
columns:
description: >
A path to a JSON file mapping columns to the attributes they are from.
required: true
group_by:
description: >
A comma-separated list of columns to group the BOM by. If not present, the
BOM will be flat.
default: ''
runs:
using: "docker"
image: "Dockerfile"
@ -25,12 +28,13 @@ runs:
- ${{ github.sha }}
- "--allspice_hub_url"
- ${{ github.server_url }}
- "--attributes_mapping"
- ${{ inputs.attributes_mapping }}
- "--columns"
- ${{ inputs.columns }}
- "--group_by"
- ${{ inputs.group_by }}
- "--output_file"
- "${{ github.workspace}}/${{ inputs.output_file_name }}"
- ${{ github.repository }}
- ${{ inputs.project_path }}
- ${{ inputs.pcb_path }}
env:
ALLSPICE_AUTH_TOKEN: ${{ github.token }}

View File

@ -11,7 +11,8 @@ import sys
from contextlib import ExitStack
from allspice import AllSpice
from allspice.utils.bom_generation import AttributesMapping, generate_bom_for_altium
from allspice.utils.bom_generation import generate_bom_for_altium
if __name__ == "__main__":
# Parse command line arguments. If you're writing a special purpose script,
@ -19,36 +20,54 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="generate_bom", description="Generate a BOM from a PrjPcb file."
)
parser.add_argument("repository", help="The repo containing the project")
parser.add_argument(
"prjpcb_file", help="The path to the PrjPcb file in the source repo."
"repository", help="The repo containing the project in the form 'owner/repo'"
)
parser.add_argument("prjpcb_file", help="The path to the PrjPcb file in the source repo.")
parser.add_argument(
"pcb_file",
help="The path to the PCB file in the source repo.",
"--columns",
help=(
"A path to a JSON file mapping columns to the attributes they are from. See the README "
"for more details. Defaults to 'columns.json'."
),
default="columns.json",
)
parser.add_argument(
"--source_ref",
help="The git reference the netlist should be generated for (eg. branch name, tag name, commit SHA). Defaults to main.",
help=(
"The git reference the BOM should be generated for (eg. branch name, tag name, commit "
"SHA). Defaults to the main branch."
),
default="main",
)
parser.add_argument(
"--allspice_hub_url",
help="The URL of your AllSpice Hub instance. Defaults to https://hub.allspice.io.",
)
parser.add_argument(
"--attributes_mapping",
help="JSON text containing the attributes mapping.",
required=True,
)
parser.add_argument(
"--output_file",
help="The path to the output file. If absent, the CSV will be output to the command line.",
)
parser.add_argument(
"--group_by",
help=(
"A comma-separated list of columns to group the BOM by. If not present, the BOM will "
"be flat."
),
)
parser.add_argument(
"--variant",
help=(
"The variant of the project to generate the BOM for. If not present, the BOM will be "
"generated for the default variant."
),
)
args = parser.parse_args()
attributes_mapper = AttributesMapping.from_dict(json.loads(args.attributes_mapping))
columns_file = args.columns
with open(columns_file, "r") as f:
columns = json.loads(f.read())
# Use Environment Variables to store your auth token. This keeps your token
# secure when sharing code.
@ -60,14 +79,12 @@ if __name__ == "__main__":
if args.allspice_hub_url is None:
allspice = AllSpice(token_text=auth_token)
else:
allspice = AllSpice(
token_text=auth_token, allspice_hub_url=args.allspice_hub_url
)
allspice = AllSpice(token_text=auth_token, allspice_hub_url=args.allspice_hub_url)
repo_owner, repo_name = args.repository.split("/")
repository = allspice.get_repository(repo_owner, repo_name)
prjpcb_file = args.prjpcb_file
pcb_file = args.pcb_file
group_by = args.group_by.split(",") if args.group_by else None
print("Generating BOM...", file=sys.stderr)
@ -75,38 +92,21 @@ if __name__ == "__main__":
allspice,
repository,
prjpcb_file,
pcb_file,
attributes_mapper,
args.source_ref,
columns,
group_by=group_by,
ref=args.source_ref,
variant=args.variant,
)
bom_rows = [
[
bom_row.manufacturer,
bom_row.part_number,
bom_row.quantity,
", ".join(bom_row.designators),
bom_row.description,
]
for bom_row in bom_rows
]
with ExitStack() as stack:
keys = bom_rows[0].keys()
if args.output_file is not None:
f = stack.enter_context(open(args.output_file, "w"))
writer = csv.writer(f)
writer = csv.DictWriter(f, fieldnames=keys)
else:
writer = csv.writer(sys.stdout)
writer = csv.DictWriter(sys.stdout, fieldnames=keys)
header = [
"Manufacturer",
"MFG Part Number",
"Quantity",
"Reference Designator",
"Description",
]
writer.writerow(header)
writer.writeheader()
writer.writerows(bom_rows)
print("Generated bom.", file=sys.stderr)