zip update

This commit is contained in:
dzaitsev
2025-05-04 13:48:21 +03:00
parent 30d97c6244
commit f100ed638d
2 changed files with 135 additions and 155 deletions
+109 -136
View File
@@ -1,47 +1,46 @@
// Jenkins Pipeline script to directly copy the zip file from an upstream job's workspace,
// derive build identifier from the zip filename, and upload to Google Drive with retention.
// Jenkins Pipeline script to find the latest zip file directly in the artifacts directory
// and upload it to Google Drive with retention.
// Retention is based on the timestamp embedded in the filename and performed entirely in PowerShell.
// Designed to run on a Windows agent.
// Designed to run on a Windows agent, specifically on the machine where the main build creates artifacts.
// Assumes rclone is installed and its directory is added to the system's PATH on the Windows agent.
pipeline {
// Agent should be your Windows VM agent
// Agent should be the SAME Windows VM agent where the main build job runs
// and creates the artifacts in the MAIN_BUILD_ARTIFACTS_DIR.
agent { label 'Win10-BuildMachine' } // Replace with your Windows agent label if different
// Removed parameters block as we don't need upstream job name/build number parameters anymore
environment {
// Google Drive settings
GDRIVE_REMOTE = 'AzaionGoogleDrive:AzaionSuiteBuilds' // Your rclone remote name and path
// Use a relative path within the workspace for the temporary directory on Windows
// This temporary directory will hold the copied zip file before upload
// This temporary directory is still useful for rclone's internal operations and cleanup
TMP_UPLOAD_DIR = 'temp_upload'
// Path to rclone.conf on the Windows agent.
// Adjust this path if your rclone.conf is located elsewhere on the Windows VM.
// Using a relative path from the workspace root is often best practice.
RCLONE_CONFIG = 'rclone.conf' // Assuming rclone.conf is in the workspace root
// Define the FULL path to the upstream job's workspace on the SAME agent
// This assumes both jobs run on the same agent and you know the workspace path structure
UPSTREAM_WORKSPACE = 'C:\\Jenkins\\workspace\\AzaionSuite' // **Adjust this path if necessary**
// Define the path to the zip file relative to the upstream workspace
// Based on your description: C:\Jenkins\workspace\AzaionSuite\suite\AzaionSuite.1.4.5-YYYYMMDD-HHMMSS.zip
// We'll use a wildcard to find the specific timestamped zip
UPSTREAM_ZIP_PATH_RELATIVE = 'suite\\*.zip' // **Reverted filter to only look for .zip**
// Number of latest files to keep on Google Drive
FILES_TO_KEEP = 3
// Define the FULL path to the directory containing the zip files.
// This job will operate directly within this directory.
// ** IMPORTANT: Replace 'C:/Jenkins/workspace/AzaionSuite/suite' with the actual path **
TARGET_ARTIFACTS_DIR = 'C:/Jenkins/workspace/AzaionSuite/suite' // <<== UPDATE THIS
// Define the name of the latest zip file found as an environment variable
// This makes it easier to reference in later stages
LATEST_ZIP_FILENAME = '' // This will be set dynamically in the 'Find Latest Zip and Upload' stage
}
stages {
stage('Initialize') {
stage('Initialize Workspace') {
steps {
echo "Initializing workspace on Windows agent..."
// Use standard Windows PowerShell for directory creation and cleanup
// Ensure paths are quoted for safety
// Ensure paths are quoted for safety and use backslashes for Windows paths
powershell """
# Create temporary upload directory
# Create temporary upload directory within THIS job's workspace
New-Item -ItemType Directory -Force -Path "${env:WORKSPACE}\\\\${env:TMP_UPLOAD_DIR}"
# Clean up previous temporary files in the upload directory
@@ -50,142 +49,114 @@ pipeline {
}
}
// Removed the 'Copy Last Stable Artifact' stage
stage('Copy and Upload Build') { // Combined stage for copying, finding name, and conditional upload
stage('Find Latest Zip and Upload') { // Renamed stage
steps {
script { // Wrap steps in a script block
echo "Starting Copy and Upload Build stage..."
echo "Starting 'Find Latest Zip and Upload' stage."
def upstreamZipFullPath = null
def copiedZipFilename = null
def copiedZipFilePath = null
def expectedZipFilenameOnDrive = null
// Change directory to the target artifacts folder where the zip files are located
dir("${env.TARGET_ARTIFACTS_DIR}") {
echo "Operating in directory: ${pwd()}"
// --- Find the full path of the zip file in the upstream workspace ---
// Use PowerShell to find the latest zip file based on filename timestamp
// This logic is similar to the 'Archive Latest Zip' stage from the combined pipeline
def powershellOutput = powershell(script: """
\$zipPattern = "AzaionSuite*-*-*.zip" # Pattern for zip files
Write-Host "Searching for latest zip file matching '\$zipPattern' in '\$PWD'..."
# Find all zip files matching the pattern
# Use -ErrorAction Stop to fail if Get-ChildItem fails
\$zipFiles = Get-ChildItem -Path . -Filter \$zipPattern -ErrorAction Stop
if (\$zipFiles.Count -eq 0) {
Write-Host "No zip files matching pattern '\$zipPattern' found in '\$PWD'."
# Exit PowerShell script with a non-zero code to fail the step
exit 1
}
Write-Host "Found \$(\$zipFiles.Count) zip file(s)."
# --- Sorting of ZIP Files by Filename Timestamp (in PowerShell) ---
Write-Host "Sorting ZIP files by filename timestamp (YYYYMMDD-HHMMSS)..."
# Regex to extract the timestamp from the filename
\$timestampRegex = '.*-(\\d{8}-\\d{6})\\.zip'
# Sort the files by extracting the timestamp and converting to DateTime for accurate sorting
# Sort-Object -Descending ensures newest are first
\$sortedZipFiles = \$zipFiles | Sort-Object -Descending {
\$name = \$_.Name
\$match = [regex]::Match(\$name, \$timestampRegex)
if (\$match.Success -and \$match.Groups.Count -gt 1) {
\$timestampStr = \$match.Groups[1].Value
# Attempt to parse the timestamp string into a DateTime object
try {
echo "Attempting to find the zip file in upstream workspace: ${env.UPSTREAM_WORKSPACE}\\\\${env.UPSTREAM_ZIP_PATH_RELATIVE}"
// Use PowerShell to find the first file matching the pattern (.zip only)
// Use -ErrorAction Stop to ensure the error is caught by Groovy try/catch
// Ensure paths are quoted for safety
upstreamZipFullPath = powershell(script: "Get-ChildItem -Path \"${env:UPSTREAM_WORKSPACE}\\\\${env:UPSTREAM_ZIP_PATH_RELATIVE}\" -ErrorAction Stop | Select-Object -First 1 -ExpandProperty FullName", returnStdout: true).trim()
if (upstreamZipFullPath) {
echo "Found upstream file: ${upstreamZipFullPath}"
// Extract just the filename from the full path
copiedZipFilename = upstreamZipFullPath.substring(upstreamZipFullPath.lastIndexOf('\\') + 1)
echo "Derived filename: ${copiedZipFilename}"
// DEBUG: Show the derived filename explicitly
echo "DEBUG: Derived copiedZipFilename = '${copiedZipFilename}'"
// --- Removed Workaround: Remove trailing .zip if it's .zip.zip ---
copiedZipFilePath = "${env:WORKSPACE}\\\\${env:TMP_UPLOAD_DIR}\\\\${copiedZipFilename}" // Path where it will be copied in THIS workspace
expectedZipFilenameOnDrive = copiedZipFilename // The name on Google Drive is the same as the original filename
[DateTime]::ParseExact(\$timestampStr, "yyyyMMdd-HHmmss", \$null)
} catch {
Write-Host "Warning: Could not parse timestamp from filename '\$name': \$(\$_.Exception.Message)"
# Handle parsing errors - treat as the oldest possible date (e.g., 1/1/0001)
# This ensures unparseable dates are placed at the end (oldest)
[DateTime]::MinValue
}
} else {
// Updated error message to reflect looking for .zip only
error("No *.zip file found in the upstream workspace '${env.UPSTREAM_WORKSPACE}\\\\${env.UPSTREAM_ZIP_PATH_RELATIVE}'. Cannot proceed.")
return // Exit script block safely
Write-Host "Warning: Filename '\$name' does not match timestamp regex."
# Handle non-matching filenames - treat as the oldest possible date
[DateTime]::MinValue
# Exit the script here if you want to fail the stage on unparseable filenames
# exit 1
}
} catch (e) {
echo "Error finding upstream file: ${e.message}"
error("Failed to find the zip file in the upstream workspace.")
return // Exit script block safely
}
// --- End Find upstream zip file name ---
# --- End Sorting ---
echo "Target copy path in this workspace: ${copiedZipFilePath}"
echo "Expected zip filename on Google Drive: ${expectedZipFilenameOnDrive}"
# Get the name of the latest zip file (the first one after sorting descending)
\$latestZipFile = \$sortedZipFiles | Select-Object -First 1
Write-Host "Identified latest zip file: '\$latestZipFile.Name'"
# Output the latest zip filename and set it as an environment variable for Jenkins
# This uses the Jenkins 'set context' feature
Write-Host "::SET-ENV::LATEST_ZIP_FILENAME=\$(\$latestZipFile.Name)"
exit 0 # Exit PowerShell script successfully
""" , returnStdout: true
) // End powershell call
// Parse the PowerShell output to find the latest zip filename and set the Groovy environment variable
def matcher = powershellOutput =~ /::SET-ENV::LATEST_ZIP_FILENAME=(.+)/
def latestZipFilename = null
if (matcher.find()) {
latestZipFilename = matcher.group(1).trim()
env.LATEST_ZIP_FILENAME = latestZipFilename // Set the environment variable
echo "Groovy set LATEST_ZIP_FILENAME to: ${env.LATEST_ZIP_FILENAME}"
} else {
error "Could not find the latest zip filename in the PowerShell output using marker."
}
// Ensure the latest zip filename environment variable is set before attempting upload
if (env.LATEST_ZIP_FILENAME && env.LATEST_ZIP_FILENAME != '') {
echo "Identified latest zip file for upload: ${env.LATEST_ZIP_FILENAME}"
// --- Get list of existing zip files on Google Drive ---
def existingZipFiles = []
try {
echo "Checking for existing zip files on Google Drive: ${GDRIVE_REMOTE}..."
// --- Upload the latest ZIP archive directly from the current directory ---
echo "Starting upload of '${env.LATEST_ZIP_FILENAME}' directly from '${pwd()}' to ${GDRIVE_REMOTE}..."
// Use standard Windows PowerShell to execute rclone (now in PATH)
// Ensure config path and remote path are quoted, and use backslashes for Windows paths
def rcloneListCommand = """
rclone --config "${env:WORKSPACE}\\\\${RCLONE_CONFIG}" lsjson "${GDRIVE_REMOTE}"
"""
def rcloneListOutput = powershell(script: rcloneListCommand, returnStdout: true).trim() ?: '[]'
if (!rcloneListOutput.startsWith('[') || !rcloneListOutput.endsWith(']')) {
echo "Warning: rclone lsjson did not return a valid JSON array for existing files check. Output: ${rcloneListOutput}"
// Continue, but assume no existing files to be safe
existingZipFiles = []
} else {
def allFilesJson = readJSON text: rcloneListOutput
// Filter for zip files and ensure Name exists
// Removed workaround application here
existingZipFiles = allFilesJson.findAll { it.Name?.endsWith(".zip") }.collect { it.Name }
// DEBUG: Print the exact list of existing zip files found (without workaround)
echo "DEBUG: Exact list of existing zip files on Google Drive: ${existingZipFiles}"
}
} catch (e) {
echo "An error occurred while checking existing files on Google Drive: ${e}"
// Continue, but assume no existing files to be safe
existingZipFiles = []
}
// --- End getting existing files list ---
// DEBUG: Print the exact expected zip filename being checked
echo "DEBUG: Checking for existence of expected zip file: ${expectedZipFilenameOnDrive}"
// --- Manual Check if the zip file already exists on Google Drive ---
def fileExistsOnDrive = false
for (existingFile in existingZipFiles) {
// Compare the original filename to the list from Google Drive (without workaround)
if (existingFile == expectedZipFilenameOnDrive) {
fileExistsOnDrive = true
break // Found a match, no need to check further
}
}
// --- End Manual Check ---
if (!fileExistsOnDrive) { // Use the result of the manual check
// If we reach here, the zip file does NOT exist on Google Drive, so proceed with copying and uploading
echo "Zip file ${expectedZipFilenameOnDrive} does not exist on Google Drive. Proceeding with copying and uploading."
try {
// --- Copy the zip file from the upstream workspace ---
// Use the original upstreamZipFullPath for the source path
echo "Copying zip file from '${upstreamZipFullPath}' to '${copiedZipFilePath}'..."
// DEBUG: Show source and destination paths for Copy-Item
echo "DEBUG: Copy-Item Source: '${upstreamZipFullPath}'"
echo "DEBUG: Copy-Item Destination: '${copiedZipFilePath}'"
// Use standard Windows PowerShell Copy-Item
// Ensure paths are quoted for safety and use backslashes
powershell "Copy-Item -Path \"${upstreamZipFullPath}\" -Destination \"${copiedZipFilePath}\" -Force"
echo "Successfully copied zip file."
// --- Upload the copied ZIP archive to Google Drive ---
// Use the original filename for the upload source path
echo "Starting upload of '${copiedZipFilename}' to ${GDRIVE_REMOTE}..."
// DEBUG: Show source path for rclone copy
echo "DEBUG: rclone copy Source: '${copiedZipFilePath}'"
// Use standard Windows PowerShell to execute rclone (now in PATH)
// The source path for rclone is the filename relative to the current directory (TARGET_ARTIFACTS_DIR)
powershell """
rclone --config "${env:WORKSPACE}\\\\${RCLONE_CONFIG}" copy \"${copiedZipFilePath}\" \"${GDRIVE_REMOTE}\"
rclone --config "${env:WORKSPACE}\\\\${env:RCLONE_CONFIG}" copy \"${env:LATEST_ZIP_FILENAME}\" \"${env:GDRIVE_REMOTE}\"
"""
echo "Finished uploading ${copiedZipFilename}."
echo "Finished uploading ${env.LATEST_ZIP_FILENAME}."
} catch (e) {
echo "ERROR processing build (copy/upload): ${e}"
// Consider adding a flag here to mark that at least one build failed processing
// This could be checked in a later post block to decide if the overall build should be marked as unstable
error("Failed to copy or upload build: ${e.message}") // Fail the stage on error
} finally {
// Clean up the copied zip file after upload attempt
// Use standard Windows PowerShell Remove-Item
echo "Cleaning up copied zip file: ${copiedZipFilePath}"
powershell "Remove-Item -Force \"${copiedZipFilePath}\" -ErrorAction SilentlyContinue"
echo "ERROR uploading build: ${e}"
error("Failed to upload latest zip file: ${e.message}") // Fail the stage on error
}
// No cleanup needed in finally block here as the file is not copied to a temp location first
} else {
// If the file DOES exist on Google Drive, print the skipping message
echo "Skipping upload: ${expectedZipFilenameOnDrive} already exists on Google Drive."
// No file was copied in this case, so no cleanup needed in finally
error "LATEST_ZIP_FILENAME environment variable was not set or was empty. Cannot upload."
}
} // End dir block
} // end script
} // end steps
} // end stage
@@ -195,7 +166,7 @@ pipeline {
script { // Wrap script logic in a script block
echo "Starting Google Drive retention process (using PowerShell)..."
// Ensure rclone is installed and in PATH on the Windows agent,
// and the Jenkins agent user has read access to '${env:WORKSPACE}\\\\${RCLONE_CONFIG}'.
// and the Jenkins agent user has read access to '${env:WORKSPACE}\\\\${env.RCLONE_CONFIG}'.
// PowerShell script block for retention logic
powershell """
@@ -242,6 +213,8 @@ pipeline {
Write-Host "Warning: Filename '\$name' does not match timestamp regex."
# Handle non-matching filenames - treat as the oldest possible date
[DateTime]::MinValue
# Exit the script here if you want to fail the stage on unparseable filenames
# exit 1
}
}
# --- End Sorting ---
+17 -10
View File
@@ -30,7 +30,7 @@ pipeline {
// Define the name of the created zip file as an environment variable
// This makes it easier to reference in later stages
CREATED_ZIP_FILENAME = '' // This will be set dynamically
CREATED_ZIP_FILENAME = '' // This will be set dynamically by capturing PowerShell output
}
stages {
@@ -49,12 +49,13 @@ pipeline {
// These are now defined as literals within the PowerShell script string
// def exePattern = 'AzaionSuite*.exe'
// def binPattern = 'AzaionSuite*.bin'
// Define defaultVersion here, used if version extraction fails
// Define defaultVersion here, used if no exe is found
// def defaultVersion = '1.0.0'
// Use a powershell step to perform file finding, filename extraction, timestamp generation, and zipping
powershell '''
// Capture the output of the powershell script
def zipFilenameOutput = powershell returnStdout: true, script: '''
$ErrorActionPreference = "Stop" # Stop the script on any error
$sevenZipExe = "$env:SEVEN_ZIP_PATH\\7z.exe"
@@ -89,7 +90,7 @@ pipeline {
# --- Zipping Logic ---
# Get current date and time in YYYYMMDD-HHmmss format
# Get current date and time inYYYYMMDD-HHmmss format
$timestamp = (Get-Date -Format "yyyyMMdd-HHmmss")
# Construct the zip filename using the base filename and timestamp
@@ -124,13 +125,19 @@ pipeline {
Write-Host "Zip archive created successfully by 7-Zip: $zipFilename"
# Output the zip filename and set it as an environment variable for Jenkins
# This uses the Jenkins 'set context' feature
Write-Host "::SET-ZIP-FILENAME::$zipFilename"
Write-Host "::SET-ENV::CREATED_ZIP_FILENAME=$zipFilename"
# Output the zip filename to standard output for the Groovy script to capture
# Write-Host "::SET-ZIP-FILENAME::$zipFilename" # Removed, using Write-Output instead
# Write-Host "::SET-ENV::CREATED_ZIP_FILENAME=$zipFilename" # Removed, using Write-Output instead
Write-Output $zipFilename
exit 0
''' // End powershell script
// Capture the output and set the environment variable
// The PowerShell script outputs the zip filename as the last line
env.CREATED_ZIP_FILENAME = zipFilenameOutput.trim()
echo "Set CREATED_ZIP_FILENAME environment variable to: ${env.CREATED_ZIP_FILENAME}"
} // End dir block
}
}
@@ -145,14 +152,14 @@ pipeline {
// The zip filename was set as an environment variable in the previous stage
def createdZipFilename = env.CREATED_ZIP_FILENAME
if (createdZipFilename) {
if (createdZipFilename && !createdZipFilename.trim().isEmpty()) {
echo "Identified created zip file for archiving: ${createdZipFilename}"
// Archive the created zip file using Jenkins built-in step
// The zip file is created in the MAIN_BUILD_ARTIFACTS_DIR by the Batch script
archiveArtifacts artifacts: "${createdZipFilename}", fingerprint: true
echo "Archive step completed."
} else {
error "CREATED_ZIP_FILENAME environment variable was not set. Cannot archive."
error "CREATED_ZIP_FILENAME environment variable was not set or was empty. Cannot archive."
}
} // End dir block
}