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,
|
||||
// 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
|
||||
|
||||
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"
|
||||
|
||||
@ -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(" 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")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user