customized for basic
All checks were successful
MVS Submit & Execute / upload-and-run (push) Successful in 6s

This commit is contained in:
Greg Gauthier 2026-02-17 21:44:56 +00:00
parent b770b1c174
commit a167f5adf5
5 changed files with 9 additions and 214 deletions

View File

@ -1,109 +0,0 @@
name: MVS Delete Members
on:
push:
branches: [ master ]
paths:
- 'src/**'
- 'jcl/**'
workflow_dispatch: # Allow manual trigger for cleanup
jobs:
delete-members:
runs-on: ubuntu-gitea
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git diff
- name: Check if workflow should run
id: check
run: |
echo "Checking if there are deleted source files..."
if git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
DELETED_FILES=$(git diff --name-only --diff-filter=D HEAD~1 2>/dev/null | grep -E '\.(c|bas)$' || true)
if [ -z "$DELETED_FILES" ]; then
echo "No deleted source files found. Skipping workflow."
echo "should_run=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "Found deleted files: $DELETED_FILES"
echo "should_run=true" >> $GITHUB_OUTPUT
else
echo "No parent commit, skipping workflow"
echo "should_run=false" >> $GITHUB_OUTPUT
fi
- name: Prepare environment
if: steps.check.outputs.should_run == 'true'
id: setup
run: |
echo "=== Debug: Starting setup ==="
apt-get update && apt install -y netcat-traditional python3-requests
nc -h
echo "=== Debug: Setup complete ==="
- name: Find deleted source files (deleted only)
if: steps.check.outputs.should_run == 'true'
id: deleted
run: |
echo "=== Debug: Starting deletion detection ==="
echo "Current dir: $(pwd)"
# Check if we have a parent commit
if git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
echo "Parent commit exists; checking for deletions."
# Use --diff-filter=D to only get Deleted files (exclude Added/Modified)
DELETED_FILES=$(git diff --name-only --diff-filter=D HEAD~1 2>/dev/null | grep -E '\.(c|bas)$')
echo "Deleted files from last commit: '${DELETED_FILES}'"
else
echo "No parent commit; no deletions to process."
DELETED_FILES=""
fi
if [ -z "$DELETED_FILES" ]; then
echo "No deleted C/BAS files found; skipping workflow."
echo "has_deletions=false" >> $GITHUB_OUTPUT
exit 0
fi
# Process deleted files - convert to space-separated list of members
DELETED_MEMBERS=""
for DFILE in $DELETED_FILES; do
DEXT="${DFILE##*.}"
DBASE=$(basename "$DFILE" ".$DEXT")
DELETED_MEMBERS="$DELETED_MEMBERS $DBASE"
done
echo "Deleted members: $DELETED_MEMBERS"
echo "deleted_members=$DELETED_MEMBERS" >> $GITHUB_OUTPUT
echo "has_deletions=true" >> $GITHUB_OUTPUT
echo "=== Debug: Deletion detection complete ==="
- name: Delete removed members from PDS
if: steps.check.outputs.should_run == 'true' && steps.deleted.outputs.has_deletions == 'true'
run: |
echo "=== Starting deletion of removed members ==="
echo "Deleted members: ${{ steps.deleted.outputs.deleted_members }}"
for MEMBER in ${{ steps.deleted.outputs.deleted_members }}; do
echo "Deleting member: $MEMBER"
python3 scripts/del_member.py "@05054.SRCLIB.C($MEMBER)"
done
echo "=== Deletion complete ==="
env:
MVS_BATCH_PASSWORD: ${{ vars.MVS_BATCH_PASSWORD }}
MVS_HOST: "oldcomputernerd.com"
- name: Report Status
if: steps.check.outputs.should_run == 'true' && steps.deleted.outputs.has_deletions == 'true'
run: |
echo "Deletion complete! Members removed from mainframe PDS."
- name: Workflow skipped
if: steps.check.outputs.should_run == 'false'
run: |
echo "Workflow skipped - no deleted source files in this commit."

View File

@ -1,5 +1,5 @@
//{NAME} JOB (GCC),'C Program',
//{NAME} JOB (BAS360),'BASIC Program',
// NOTIFY=@05054,CLASS=A,MSGCLASS=A,
// MSGLEVEL=(1,1),REGION=4M,TIME=1440
//STEP1 EXEC GCCCG,INFILE='@05054.SRCLIB.C({NAME})'
//STEP1 EXEC GCCCG,INFILE='@05054.SRCLIB.BAS({NAME})'
//

View File

@ -32,7 +32,7 @@ if ! [[ "$NAME" =~ ^[A-Z][A-Z0-9]*$ ]]; then
fi
JCL_FILE="jcl/${NAME}.jcl"
SRC_FILE="src/${NAME}.c"
SRC_FILE="src/${NAME}.bas"
# Check if files already exist
if [ -f "$JCL_FILE" ]; then
@ -51,7 +51,7 @@ if [ ! -f "jcl/TEMPLATE.jcl" ]; then
exit 1
fi
echo "Creating new C project: $NAME"
echo "Creating new BAS project: $NAME"
echo ""
# Replace {NAME} placeholders in template
@ -65,5 +65,5 @@ echo "✓ Created source: $SRC_FILE"
echo ""
echo "Project '$NAME' created successfully!"
echo "Next steps:"
echo " 1. Edit $SRC_FILE with your C code"
echo " 1. Edit $SRC_FILE with your BASIC code"
echo " 2. Commit and push to trigger mainframe build"

View File

@ -1,96 +0,0 @@
#!/usr/bin/env python3
import sys
import subprocess
import tempfile
import os
# Force temp files into a folder inside your project
custom_temp_dir = os.path.join(os.getcwd(), "tmp")
os.makedirs(custom_temp_dir, exist_ok=True)
tempfile.tempdir = custom_temp_dir
MVSHOST = "oldcomputernerd.com"
RDRPORT = 3505
MVS_PASSWORD = os.environ.get("MVS_BATCH_PASSWORD")
def create_delete_jcl(dataset_name, member_name):
"""Create JCL to delete a PDS member using IEHPROGM"""
jcl = f"""
//DELETE JOB (ACCT),'DELETE',
// USER=@05054,PASSWORD={MVS_PASSWORD},
// CLASS=A,MSGCLASS=H,NOTIFY=@05054
//DELMEM EXEC PGM=IEHPROGM
//SYSPRINT DD SYSOUT=*
//DD1 DD DSN={dataset_name},DISP=SHR
//SYSIN DD *
SCRATCH DSNAME={dataset_name},MEMBER={member_name}
/*
"""
return jcl
def delete_member(dataset_name, member_name, mvshost=MVSHOST):
"""Delete a member from MVS PDS"""
payload = create_delete_jcl(dataset_name, member_name)
# Write JCL to temporary file and submit via netcat
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.jcl') as tmpfile:
tmpfile.write(payload)
tmpfile.flush()
tmpfile_path = tmpfile.name
try:
with open(tmpfile_path, 'rb') as f:
result = subprocess.run(
['nc', '-w', '5', mvshost, str(RDRPORT)],
input=f.read(),
check=True,
capture_output=True
)
print(f"Deleted {dataset_name}({member_name})")
if result.stdout:
print("JES response:", result.stdout.decode(errors='ignore').strip())
return 0
except subprocess.CalledProcessError as e:
print(f"Deletion failed: {e}")
print("stderr:", e.stderr.decode(errors='ignore'))
return 1
finally:
os.unlink(tmpfile_path)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: delete_mvs_member.py <pds_destination> [mvshost]")
print()
print("Arguments:")
print(" pds_destination - PDS destination as DATASET(MEMBER) (required)")
print(" mvshost - MVS host (optional, default: oldcomputernerd.com)")
print()
print("Examples:")
print(" delete_mvs_member.py '@05054.SRCLIB.C(SIEVE11)'")
print(" delete_mvs_member.py '@05054.SRCLIB.C(HELLO)' mainframe.example.com")
sys.exit(1)
destination = sys.argv[1]
# Parse PDS syntax: DATASET(MEMBER)
if '(' in destination and destination.endswith(')'):
dataset_name = destination[:destination.index('(')]
member_name = destination[destination.index('(')+1:-1]
else:
print(f"Error: Invalid PDS syntax '{destination}'. Use format: DATASET(MEMBER)")
sys.exit(1)
# Optional host override
mvshost = sys.argv[2] if len(sys.argv) > 2 else MVSHOST
print(f"Deleting: {dataset_name}({member_name})")
print(f"Host: {mvshost}")
print()
sys.exit(delete_member(dataset_name, member_name, mvshost))

View File

@ -150,13 +150,13 @@ if __name__ == "__main__":
print("Arguments:")
print(" local_source_file - Path to source file (required)")
print(" destination_pds - PDS destination as DATASET(MEMBER) (optional)")
print(" Default: @05054.C90.SOURCE(basename)")
print(" Default: @05054.SRCLIB.BAS(basename)")
print(" mvshost - MVS host (optional, default: oldcomputernerd.com)")
print()
print("Examples:")
print(" mvs_job.py src/sieve11.c")
print(" mvs_job.py src/sieve11.c '@05054.C90.SOURCE(SIEVE11)'")
print(" mvs_job.py src/hello.c '@05054.C90.SOURCE(HELLO)' mainframe.example.com")
print(" mvs_job.py src/sieve11.bas")
print(" mvs_job.py src/sieve11.bas '@05054.SRCLIB.BAS(SIEVE11)'")
print(" mvs_job.py src/hello.bas '@05054.SRCLIB.BAS(HELLO)' mainframe.example.com")
print()
print("Notes:")
print(" - JCL file is assumed to be jcl/<basename>.jcl")