customized for basic
All checks were successful
MVS Submit & Execute / upload-and-run (push) Successful in 6s
All checks were successful
MVS Submit & Execute / upload-and-run (push) Successful in 6s
This commit is contained in:
parent
b770b1c174
commit
a167f5adf5
@ -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."
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
//{NAME} JOB (GCC),'C Program',
|
//{NAME} JOB (BAS360),'BASIC Program',
|
||||||
// NOTIFY=@05054,CLASS=A,MSGCLASS=A,
|
// NOTIFY=@05054,CLASS=A,MSGCLASS=A,
|
||||||
// MSGLEVEL=(1,1),REGION=4M,TIME=1440
|
// MSGLEVEL=(1,1),REGION=4M,TIME=1440
|
||||||
//STEP1 EXEC GCCCG,INFILE='@05054.SRCLIB.C({NAME})'
|
//STEP1 EXEC GCCCG,INFILE='@05054.SRCLIB.BAS({NAME})'
|
||||||
//
|
//
|
||||||
@ -32,7 +32,7 @@ if ! [[ "$NAME" =~ ^[A-Z][A-Z0-9]*$ ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
JCL_FILE="jcl/${NAME}.jcl"
|
JCL_FILE="jcl/${NAME}.jcl"
|
||||||
SRC_FILE="src/${NAME}.c"
|
SRC_FILE="src/${NAME}.bas"
|
||||||
|
|
||||||
# Check if files already exist
|
# Check if files already exist
|
||||||
if [ -f "$JCL_FILE" ]; then
|
if [ -f "$JCL_FILE" ]; then
|
||||||
@ -51,7 +51,7 @@ if [ ! -f "jcl/TEMPLATE.jcl" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Creating new C project: $NAME"
|
echo "Creating new BAS project: $NAME"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Replace {NAME} placeholders in template
|
# Replace {NAME} placeholders in template
|
||||||
@ -65,5 +65,5 @@ echo "✓ Created source: $SRC_FILE"
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Project '$NAME' created successfully!"
|
echo "Project '$NAME' created successfully!"
|
||||||
echo "Next steps:"
|
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"
|
echo " 2. Commit and push to trigger mainframe build"
|
||||||
|
|||||||
@ -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))
|
|
||||||
@ -150,13 +150,13 @@ if __name__ == "__main__":
|
|||||||
print("Arguments:")
|
print("Arguments:")
|
||||||
print(" local_source_file - Path to source file (required)")
|
print(" local_source_file - Path to source file (required)")
|
||||||
print(" destination_pds - PDS destination as DATASET(MEMBER) (optional)")
|
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(" mvshost - MVS host (optional, default: oldcomputernerd.com)")
|
||||||
print()
|
print()
|
||||||
print("Examples:")
|
print("Examples:")
|
||||||
print(" mvs_job.py src/sieve11.c")
|
print(" mvs_job.py src/sieve11.bas")
|
||||||
print(" mvs_job.py src/sieve11.c '@05054.C90.SOURCE(SIEVE11)'")
|
print(" mvs_job.py src/sieve11.bas '@05054.SRCLIB.BAS(SIEVE11)'")
|
||||||
print(" mvs_job.py src/hello.c '@05054.C90.SOURCE(HELLO)' mainframe.example.com")
|
print(" mvs_job.py src/hello.bas '@05054.SRCLIB.BAS(HELLO)' mainframe.example.com")
|
||||||
print()
|
print()
|
||||||
print("Notes:")
|
print("Notes:")
|
||||||
print(" - JCL file is assumed to be jcl/<basename>.jcl")
|
print(" - JCL file is assumed to be jcl/<basename>.jcl")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user