Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `.gitattributes` reclassify `.st` files as iec-st:
** linguist-vendored
# *.ppjs linguist-language=ST
315 changes: 315 additions & 0 deletions .github/workflows/generate_assesment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@

# This GitHub Actions workflow generates an assessment Excel file for SIMATIC AX projects
# and automatically creates an issue with download links and notification emails.
#
# Workflow Structure:
# 1. collect-info: Gathers project information and creates info.yml artifact
# 2. fill-excel: Downloads info, generates Excel file, and uploads as artifact
# 3. notify: Creates GitHub issue with download links and email notification
#
# The workflow is triggered manually via workflow_dispatch with two required inputs:
# - EXACT_Ticket_ID: The EX Classification Ticket number
# - Approver: The business approver (Promotor BL) selected from predefined options
#
# Artifacts generated:
# - info-yml: Contains collected project information
# - assessment-excel: The generated questionnaire Excel file
#
# The final issue includes direct links to the workflow run for artifact download
# and a mailto link for email notification to the actor.
name: Start Assessment
on:
workflow_dispatch:
inputs:
EXACT_Ticket_ID:
description: 'Your EX Classification Ticket'
required: true
default: '0000'
Approver:
description: 'Promotor BL (Approver from Business Side to release)'
required: true
type: string
MainContribution:
description: 'Main Contribution of the Project'
required: true
type: choice
options:
- 'Documentation'
- 'ST-Code'
- 'SCL-Code'
- 'Other programming languages'
default: 'Documentation'

jobs:
# Job 1: Collect project information and create info.yml artifact
# Uses simatic-ax internal action to gather project details, ticket info, and approver data
collect-info:
runs-on: ubuntu-latest
steps:
# Checkout the repository to access project files
- name: Checkout repository
uses: actions/checkout@v4

# Set up Python environment for the collection script
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

# Install required Python dependencies for info collection
- name: Install Python dependencies
run: |
python3 -m pip install requests pyyaml openpyxl

# Collect project information using internal Simatic AX action
# This creates an info.yml file with project details, ticket ID, and approver
- name: Collect Info
uses: simatic-ax/internal-actions/collect-assessment-information@main
with:
project_name: ${{ github.repository }}
username: ${{ github.actor }}
token: ${{ secrets.READ_USER_TOKEN }}
ticket_id: ${{ inputs.EXACT_Ticket_ID }}
approver: ${{ inputs.Approver }}

# ✅ FIX YAML formatting for multi-line fields
# This ensures detailed_description and other multi-line fields are properly formatted
- name: Fix YAML formatting for multi-line fields
run: |
python3 << 'EOF'
import yaml
import re

# Read the generated info.yml
with open('info.yml', 'r') as f:
raw_content = f.read()

# Use regex to identify and fix multi-line fields that lack proper YAML syntax
lines = raw_content.split('\n')
fixed_lines = []
i = 0

while i < len(lines):
line = lines[i]

# Check if this is detailed_description field
if line.startswith('detailed_description:') and not '|' in line and not '>' in line:
# Extract the field name and first line of content
match = re.match(r'(detailed_description:)\s+(.*)', line)
if match:
field_name = match.group(1)
first_content = match.group(2)

# Start building the multi-line field with |
fixed_lines.append(f"{field_name} |")

# Add the first line of content with proper indentation
if first_content.strip():
fixed_lines.append(f" {first_content}")

# Collect all following lines that belong to this field
i += 1
while i < len(lines):
next_line = lines[i]

# Check if this line starts a new YAML key
if next_line and not next_line[0].isspace() and ':' in next_line:
i -= 1
break

# Add this line as part of the multi-line content
if next_line.strip():
fixed_lines.append(f" {next_line}")
else:
fixed_lines.append("")

i += 1
else:
fixed_lines.append(line)

i += 1

fixed_content = '\n'.join(fixed_lines)

# Validate the fixed YAML by parsing it
try:
parsed = yaml.safe_load(fixed_content)
print("✅ YAML validation successful!")
print(f"✅ Fields parsed: {', '.join(parsed.keys())}")
except yaml.YAMLError as e:
print(f"❌ YAML validation failed: {e}")
exit(1)

# Write the fixed content back
with open('info.yml', 'w') as f:
f.write(fixed_content)

print("✅ YAML formatting fixed and validated!")
EOF

# Validate the YAML file format
- name: Validate info.yml syntax
run: |
python3 << 'EOF'
import yaml

try:
with open('info.yml', 'r') as f:
data = yaml.safe_load(f)

print("✅ info.yml is valid YAML")
print(f"✅ Organization: {data.get('organization', 'N/A')}")
print(f"✅ Project: {data.get('project_name', 'N/A')}")
print(f"✅ Ticket ID: {data.get('ticket_id', 'N/A')}")
print(f"✅ Approver: {data.get('approver', 'N/A')}")

# Check critical fields
required_fields = ['organization', 'project_name', 'ticket_id', 'approver']
missing = [f for f in required_fields if f not in data]

if missing:
print(f"⚠️ Missing fields: {', '.join(missing)}")
exit(1)

print("✅ All required fields present!")

except yaml.YAMLError as e:
print(f"❌ YAML parsing error: {e}")
exit(1)
except Exception as e:
print(f"❌ Error: {e}")
exit(1)
EOF

# Upload the fixed info.yml as an artifact for use in subsequent jobs
- name: Upload info.yml artifact
uses: actions/upload-artifact@v3
with:
name: info-yml
path: info.yml

# Debug: Display info.yml content for verification
- name: Display info.yml content (Debug)
run: |
echo "=== Generated info.yml ==="
cat info.yml
echo "=== End of info.yml ==="

# Job 2: Generate the assessment Excel file using the collected information
# Downloads info.yml artifact and creates the questionnaire Excel file
fill-excel:
runs-on: ubuntu-latest
needs: collect-info # Wait for info collection to complete
steps:
# Checkout repository for Excel generation scripts
- name: Checkout repository
uses: actions/checkout@v4

# Set up Python environment for Excel generation
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

# Install Python dependencies required for Excel file creation
- name: Install Python dependencies
run: |
python3 -m pip install requests pyyaml openpyxl

# Download the info.yml artifact created in the previous job
- name: Download info.yml
uses: actions/download-artifact@v3
with:
name: info-yml

# Verify the downloaded info.yml is valid
- name: Verify downloaded info.yml
run: |
python3 << 'EOF'
import yaml

try:
with open('info.yml', 'r') as f:
data = yaml.safe_load(f)
print("✅ Downloaded info.yml is valid!")
print(f"✅ Ticket ID: {data.get('ticket_id')}")
except Exception as e:
print(f"❌ Invalid info.yml: {e}")
exit(1)
EOF

# Generate the assessment Excel file using internal Simatic AX action
# This creates a Questionnaire_Contribution_*.xlsx file
- name: Create Assessment Excel-File
uses: simatic-ax/internal-actions/create-assessment-excel@main

# Upload the generated Excel file as an artifact for download
- name: Upload Excel artifact
uses: actions/upload-artifact@v3
with:
name: assessment-excel
path: Questionnaire_Contribution_*.xlsx

# Print workflow run information for reference
- name: Print Run ID and artifact locations
run: |
echo "✅ Assessment workflow completed successfully!"
echo ""
echo "📊 Workflow Information:"
echo " Run ID: ${{ github.run_id }}"
echo " Repository: ${{ github.repository }}"
echo " Actor: ${{ github.actor }}"
echo ""
echo "📁 Artifacts available at:"
echo " https://github.siemens.cloud/${{ github.repository }}/actions/runs/${{ github.run_id }}"
echo ""
echo "⏱️ Artifacts will be available for 90 days"

# Job 3: Trigger notification workflow with direct artifact links
trigger-notify:
runs-on: ubuntu-latest
needs: fill-excel
if: success()
steps:
# Download info.yml to extract ticket information for notification
- name: Download info.yml
uses: actions/download-artifact@v3
with:
name: info-yml

# Extract ticket ID and email for notification content
- name: Extract notification info
id: extract-info
run: |
python3 << 'PYEOF'
import yaml

with open('info.yml', 'r') as f:
data = yaml.safe_load(f)

scd_mail = data.get('scd_mail', 'unknown@siemens.com')
ticket_id = data.get('ticket_id', 'UNKNOWN')

with open('${{ github.output }}', 'a') as f:
f.write(f"scd_mail={scd_mail}\n")
f.write(f"ticket_id={ticket_id}\n")
PYEOF

# Trigger the separate notification workflow with direct artifact links
- name: Trigger notification workflow
run: |
curl -X POST \
-H "Authorization: token ${{ secrets.GH_ISSUE_CREATOR_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://github.siemens.cloud/api/v3/repos/${{ github.repository }}/actions/workflows/notify-assessment.yml/dispatches" \
-d "{
\"ref\": \"main\",
\"inputs\": {
\"run_id\": \"${{ github.run_id }}\",
\"repository\": \"${{ github.repository }}\",
\"actor\": \"${{ github.actor }}\",
\"ticket_id\": \"${{ steps.extract-info.outputs.ticket_id }}\",
\"scd_mail\": \"${{ steps.extract-info.outputs.scd_mail }}\"
}
}"
continue-on-error: true
72 changes: 72 additions & 0 deletions .github/workflows/notify-assessment-completion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Notification workflow for assessment Excel file completion
# This workflow is triggered by the generate_assessment workflow to create
# GitHub issues with direct artifact download links after workflow completion.
#
# The workflow fetches artifacts from the specified run ID and creates
# direct download links for each artifact in the GitHub issue.

name: 'Create Assessment Notification Issue'
# description: 'Creates a GitHub issue with artifact download links for completed assessment workflows'

on:
workflow_dispatch:
inputs:
run_id:
description: 'Run ID of the completed assessment workflow'
required: true
type: string
repository:
description: 'Repository name in format owner/repo'
required: true
type: string
actor:
description: 'GitHub username of the person who triggered the original workflow'
required: false
type: string

jobs:
create-notification-issue:
runs-on: ubuntu-latest
steps:
# Download info.yml artifact from the specified workflow run
- name: Download info.yml artifact
run: |
# Get artifacts from the specified run
ARTIFACTS_JSON=$(curl -s -H "Authorization: token ${{ secrets.GH_ISSUE_CREATOR_TOKEN }}" \
"https://github.siemens.cloud/api/v3/repos/${{ inputs.repository }}/actions/runs/${{ inputs.run_id }}/artifacts")

# Find info-yml artifact
INFO_ARTIFACT_ID=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[] | select(.name == "info-yml") | .id')

if [ -n "$INFO_ARTIFACT_ID" ] && [ "$INFO_ARTIFACT_ID" != "null" ]; then
echo "Downloading info-yml artifact (ID: $INFO_ARTIFACT_ID)"

# Download the artifact
curl -L -H "Authorization: token ${{ secrets.GH_ISSUE_CREATOR_TOKEN }}" \
"https://github.siemens.cloud/api/v3/repos/${{ inputs.repository }}/actions/artifacts/$INFO_ARTIFACT_ID/zip" \
-o info-yml.zip

# Extract the zip file
unzip -q info-yml.zip

if [ -f "info.yml" ]; then
echo "Successfully downloaded and extracted info.yml"
cat info.yml
else
echo "Warning: info.yml not found in artifact"
touch info.yml # Create empty file as fallback
fi
else
echo "Warning: info-yml artifact not found, creating empty info.yml"
touch info.yml
fi

# Create GitHub issue using the new comprehensive action
- name: Create Assessment Notification Issue
uses: simatic-ax/internal-actions/create-assessment-issue@v1
with:
run_id: ${{ inputs.run_id }}
info_file: info.yml
github_token: ${{ secrets.GH_ISSUE_CREATOR_TOKEN }}
repository: ${{ inputs.repository }}
actor: ${{ inputs.actor }}
Loading
Loading