能否在Jenkins流水线运行的脚本中添加构建制品?附Python场景问询
Hey there! Let's tackle your two Jenkins artifact questions—they're both super common scenarios, so I’ve got straightforward solutions for you.
Absolutely, this is the most straightforward use case using Jenkins' built-in tools. You don’t need anything fancy here—just use the archiveArtifacts step right in your Jenkinsfile. It’s designed exactly for this purpose.
Here’s a quick example of how to use it, both for static and semi-dynamic artifact paths:
pipeline { agent any stages { stage('Build & Generate Artifacts') { steps { // Your build/generation commands go here sh 'mkdir -p dist && echo "sample artifact" > dist/my-output.txt' } } } post { always { // Archive a single specific file archiveArtifacts artifacts: 'dist/my-output.txt', fingerprint: true // Or archive all files in a directory (handles semi-dynamic names) archiveArtifacts artifacts: 'logs/*.log', allowEmptyArchive: true } } }
If your artifacts have fully dynamic names (like timestamps), you can even store the path in a Groovy variable earlier in the pipeline and pass it to archiveArtifacts—Jenkins will resolve it at runtime.
Yes, this is totally doable! Using Jenkins' REST API lets you push the artifact directly from your Python script, which is perfect for when you’re generating logs with unique, runtime-only names.
Here’s a complete Python example that handles the upload:
import requests from requests.auth import HTTPBasicAuth import sys def upload_jenkins_artifact(build_url, artifact_file_path, jenkins_user, jenkins_token): # Jenkins API endpoint for uploading artifacts to a specific build upload_endpoint = f"{build_url.rstrip('/')}/artifact" try: with open(artifact_file_path, 'rb') as artifact_file: # Send the POST request to upload the file response = requests.post( upload_endpoint, auth=HTTPBasicAuth(jenkins_user, jenkins_token), files={'file': artifact_file} ) if response.status_code == 201: print(f"✅ Successfully uploaded log file: {artifact_file_path}") else: print(f"❌ Upload failed: {response.status_code} - {response.text}") except FileNotFoundError: print(f"⚠️ Error: Log file {artifact_file_path} not found!") if __name__ == "__main__": # Get the build URL from pipeline environment variables (passed via command line) if len(sys.argv) < 2: print("Error: Please pass the Jenkins build URL as an argument") sys.exit(1) BUILD_URL = sys.argv[1] # Replace with your dynamically generated log path DYNAMIC_LOG_PATH = "./runtime_logs/run_$(date +%Y%m%d_%H%M%S).log" # Example dynamic name # Replace with your Jenkins credentials (API token from user settings) JENKINS_USER = "your-jenkins-username" JENKINS_TOKEN = "your-api-token" upload_jenkins_artifact(BUILD_URL, DYNAMIC_LOG_PATH, JENKINS_USER, JENKINS_TOKEN)
Key Notes for This Approach:
- Passing the Build URL to Python: When running your Python script from the pipeline, inject the current build’s URL as an environment variable. In your Jenkinsfile:
stage('Run Python Script') { steps { sh 'python your_log_generator.py "${BUILD_URL}"' } } - Permissions: Make sure your Jenkins user has the
Job/Updatepermission for the pipeline job—this is required to upload artifacts via the API. - API Token: You can generate an API token from your Jenkins user profile (Settings > API Tokens).
Why This Is Better Than Other Inconvenient Options
You mentioned other methods feel clunky, and I totally agree:
- Wildcard
archiveArtifacts: Works if your log name follows a pattern, but risks archiving unintended files if the wildcard is too broad. - Writing Log Path to a File: You could have Python write the log path to a text file, then read it in the Jenkinsfile to pass to
archiveArtifacts. But this adds extra I/O steps and is less direct. - Custom Plugins: Some plugins handle dynamic artifacts, but they add maintenance overhead and might not be as flexible as a direct API call from your script.
The REST API method keeps the logic contained within your Python script, which is clean and avoids extra pipeline complexity.
内容的提问来源于stack exchange,提问作者MatBailey

