One commit from the sister site, purely additive: a read-only `batches` command
so an operator working from the shell can find a batchid to undo, and a README
covering the four WINC commands. Two new files under scripts/site_imports/winc/,
nothing existing touched.
Verified rather than assumed: it changes none of the files fixed in 13be0ef9
(the workflow YAML, the approval check, the agentpackage description, the upload
audit), the gate passes, all five workflows still parse, and the project map is
current.
Suite 2369.
Scope: product
92 lines
2.9 KiB
Python
92 lines
2.9 KiB
Python
"""WINC machine adoption - BATCHES (list applied/undone import batches).
|
|
|
|
A read-only companion to writer.py and undo.py: it prints the WINC batches
|
|
newest-first so an operator can find a batchid to feed `--batch` into the undo
|
|
CLI. Like the other WINC commands it is WINC-named only for discoverability; the
|
|
underlying importbatches table is import-agnostic, so this simply filters to the
|
|
winc-machine-adoption kind.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(
|
|
os.path.dirname(os.path.abspath(__file__))))))
|
|
|
|
from dotenv import load_dotenv
|
|
from pathlib import Path
|
|
|
|
load_dotenv(Path(__file__).resolve().parents[3] / '.env')
|
|
|
|
from sqlalchemy import text
|
|
|
|
from scripts.site_imports.winc.dry_run import build_app_connection
|
|
|
|
_KIND = 'winc-machine-adoption'
|
|
|
|
|
|
def _iso(value):
|
|
# PyMySQL hands back datetime objects; SQLite hands back the stored ISO
|
|
# string. Normalise both to an ISO string so the output is stable.
|
|
if value is None:
|
|
return '-'
|
|
if hasattr(value, 'isoformat'):
|
|
return value.isoformat()
|
|
return str(value)
|
|
|
|
|
|
def list_batches(connection, limit):
|
|
rows = connection.execute(text(
|
|
'SELECT batchid, kind, rowcount, createdat, createdby, status, '
|
|
'undoneat FROM importbatches WHERE kind = :kind '
|
|
'ORDER BY createdat DESC LIMIT :limit'),
|
|
{'kind': _KIND, 'limit': limit}).fetchall()
|
|
return [
|
|
{'batchid': r[0], 'kind': r[1], 'rowcount': r[2],
|
|
'createdat': _iso(r[3]), 'createdby': r[4], 'status': r[5],
|
|
'undoneat': _iso(r[6])}
|
|
for r in rows
|
|
]
|
|
|
|
|
|
def _print_table(batches):
|
|
if not batches:
|
|
print('No WINC import batches found.')
|
|
return
|
|
header = '%-36s %-8s %5s %-20s %-16s %s' % (
|
|
'batchid', 'status', 'rows', 'createdat', 'createdby', 'undoneat')
|
|
print(header)
|
|
print('-' * len(header))
|
|
for batch in batches:
|
|
print('%-36s %-8s %5s %-20s %-16s %s' % (
|
|
batch['batchid'], batch['status'], batch['rowcount'],
|
|
batch['createdat'], batch['createdby'] or '-', batch['undoneat']))
|
|
|
|
|
|
def main(argv=None):
|
|
parser = argparse.ArgumentParser(
|
|
description='List applied/undone WINC import batches, newest first.')
|
|
parser.add_argument('--limit', type=int, default=50,
|
|
help='Maximum number of batches to show (default 50).')
|
|
parser.add_argument('--json', action='store_true',
|
|
help='Emit the batches as JSON instead of a table.')
|
|
args = parser.parse_args(argv)
|
|
|
|
if args.limit < 1:
|
|
parser.error('--limit must be a positive integer')
|
|
|
|
_app, connection = build_app_connection()
|
|
batches = list_batches(connection, args.limit)
|
|
|
|
if args.json:
|
|
import json
|
|
print(json.dumps(batches, indent=2))
|
|
else:
|
|
_print_table(batches)
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|