{"repo": "a7t-ai/slipway", "files": {"scripts/workflows/generate_release_notes.sh": {"5897e50b1e47148e4a173108a030291af2f48ab4": {"t": 1785745945.7637355, "n": 10741, "h": "13b2296176f53727", "c": "#!/bin/bash\n\n# ==========================================\n# GENERATE RELEASE NOTES SCRIPT (BASH VERSION)\n# ==========================================\n# This script generates AI-powered release notes using DeepSeek API\n# and translates them to multiple languages using bash and curl\n#\n# Usage:\n# ./scripts/workflows/generate_release_notes.sh --type custom --changes \"change1;change2\"\n# ./scripts/workflows/generate_release_notes.sh --type default --note \"default note\"\n# ./scripts/workflows/generate_release_notes.sh --changes-file CHANGES_IN_VERSION.md\n#\n# Prefer --changes-file in CI: it reads the changelog straight from disk so the\n# text never has to be threaded back through the workflow (see SHELL-SAFETY note).\n#\n# Environment Variables:\n# DEEPSEEK_API_KEY - Required for AI generation\n\nset -e\n\n# Default values\nTYPE=\"\"\nCHANGES=\"\"\nNOTE=\"\"\nCHANGES_FILE=\"\"\n\n# Parse command line arguments\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --type)\n TYPE=\"$2\"\n shift 2\n ;;\n --changes)\n CHANGES=\"$2\"\n shift 2\n ;;\n --note)\n NOTE=\"$2\"\n shift 2\n ;;\n --changes-file)\n CHANGES_FILE=\"$2\"\n shift 2\n ;;\n *)\n echo \"Unknown parameter: $1\"\n exit 1\n ;;\n esac\ndone\n\n# ---------------------------------------------------------------------------\n# SHELL-SAFETY: read release-notes text straight from CHANGES_IN_VERSION.md.\n#\n# The workflow used to extract these strings and pass them back as\n# --changes/--note. Threading free-form text (apostrophes, \"quotes\") through a\n# workflow run: block breaks shell parsing (\"unexpected EOF while looking for\n# matching '\"). Parsing the file here keeps that text out of the workflow.\n# Do NOT reintroduce inline ${{ }} interpolation of changelog text into a\n# run: block β€” read the file (this mode) or pass via env: and read \"$VAR\".\n# ---------------------------------------------------------------------------\nparse_changes_file() {\n local file=\"$1\"\n if [ ! -f \"$file\" ]; then\n echo \"❌ Error: changes file not found: $file\"\n exit 1\n fi\n\n # Custom changes = bullet lines that appear before the \"Default\" header.\n # Match \"- \" (dash + space) so real bullets qualify but markdown comment\n # delimiters like \"-->\" or \"---\" rules never get mistaken for a bullet.\n local custom_changes\n custom_changes=$(awk '/### Default Release Notes/{exit} 1' \"$file\" | grep '^- ' || true)\n\n if [ -n \"$custom_changes\" ]; then\n TYPE=\"custom\"\n # Strip \"- \" and join bullets with ';' (generate splits back on ';').\n CHANGES=$(printf '%s\\n' \"$custom_changes\" | sed 's/^- //' | tr '\\n' ';' | sed 's/;$//')\n echo \"βœ… Using custom changes from $file\"\n else\n # No custom changes -> pick a random default note.\n local default_notes count line\n default_notes=$(awk '/### Default Release Notes/{flag=1; next} /^###/{flag=0} flag' \"$file\" | grep '^- ' || true)\n if [ -z \"$default_notes\" ]; then\n echo \"❌ Error: no release notes found in $file\"\n exit 1\n fi\n count=$(printf '%s\\n' \"$default_notes\" | grep -c '^- ')\n line=$(( RANDOM % count + 1 ))\n TYPE=\"default\"\n NOTE=$(printf '%s\\n' \"$default_notes\" | sed -n \"${line}p\" | sed 's/^- //')\n echo \"🎲 Using random default note from $file\"\n fi\n}\n\nif [ -n \"$CHANGES_FILE\" ]; then\n parse_changes_file \"$CHANGES_FILE\"\nfi\n\n# Validate required arguments\nif [ -z \"$TYPE\" ]; then\n echo \"❌ Error: --type is required (custom or default)\"\n exit 1\nfi\n\nif [ -z \"$DEEPSEEK_API_KEY\" ]; then\n echo \"❌ Error: DEEPSEEK_API_KEY environment variable is required\"\n exit 1\nfi\n\n# Load copywriting persona (voice, tone, anti-slop rules) to steer the model\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPERSONA_FILE=\"$SCRIPT_DIR/copywriting_persona.md\"\nif [ -f \"$PERSONA_FILE\" ]; then\n PERSONA_CONTENT=$(cat \"$PERSONA_FILE\")\nelse\n echo \"⚠️ Warning: copywriting_persona.md not found at $PERSONA_FILE; falling back to default system prompt\"\n PERSONA_CONTENT=\"\"\nfi\n\n# JSON-escape stdin for safe embedding in a JSON payload\njson_escape() {\n python3 -c 'import json,sys; sys.stdout.write(json.dumps(sys.stdin.read()))'\n}\n\n# Function to call DeepSeek API\ncall_deepseek_api() {\n local prompt=\"$1\"\n local max_tokens=\"${2:-150}\"\n\n local system_message=\"You are a helpful assistant that creates App Store release notes for an iOS app. Be concise, engaging, and user-friendly. Focus on benefits to users.\"\n if [ -n \"$PERSONA_CONTENT\" ]; then\n system_message=\"${system_message}\n\nFollow the voice, tone, and writing rules defined in the persona below. Pay special attention to the Anti-Slop Rules (banned phrases and patterns) and the rule against em dashes and en dashes.\n\n--- PERSONA ---\n${PERSONA_CONTENT}\n--- END PERSONA ---\"\n fi\n\n local escaped_system\n escaped_system=$(printf '%s' \"$system_message\" | json_escape)\n local escaped_user\n escaped_user=$(printf '%s' \"$prompt\" | json_escape)\n\n local json_payload=$(cat <&2\n call_deepseek_api \"$prompt\" 200\n}\n\n# Function to translate text\ntranslate_text() {\n local text=\"$1\"\n local target_language=\"$2\"\n local language_name=\"$3\"\n\n echo \"🌍 Translating to $language_name...\" >&2\n\n local prompt=\"Translate this App Store release note to $target_language:\n\n\\\"$text\\\"\n\nTranslation guidelines:\n- Convert idioms and expressions to their natural equivalents in the target language\n- Do NOT use literal word-for-word translations\n- Adapt cultural references to be appropriate for the target audience\n- Ensure it sounds completely natural to native speakers\n- Keep the same tone, style, and message intent\n- Maintain the same formatting (single paragraph, no dashes)\n\nProvide only the translation, no explanations.\"\n\n call_deepseek_api \"$prompt\" 250\n}\n\n# Generate English release notes\necho \"πŸ“ Generating AI-powered release notes...\"\nENGLISH_NOTES=$(generate_release_notes)\n\nif [ -z \"$ENGLISH_NOTES\" ]; then\n echo \"❌ Failed to generate English release notes\"\n exit 1\nfi\n\necho \"βœ… Generated English release notes\"\n\n# Generate translations\nGERMAN_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"German\" \"German\")\nPORTUGUESE_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Portuguese (Brazil)\" \"Portuguese (Brazil)\")\nSPANISH_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Spanish (Spain)\" \"Spanish (Spain)\")\n\n# Validate all translations were generated\nif [ -z \"$GERMAN_NOTES\" ] || [ -z \"$PORTUGUESE_NOTES\" ] || [ -z \"$SPANISH_NOTES\" ]; then\n echo \"❌ Failed to generate all translations\"\n exit 1\nfi\n\necho \"βœ… Generated all translations\"\n\n# Output to GitHub Actions using heredoc for multiline strings\n{\n echo \"english_notes<> $GITHUB_OUTPUT\n\n{\n echo \"german_notes<> $GITHUB_OUTPUT\n\n{\n echo \"portuguese_notes<> $GITHUB_OUTPUT\n\n{\n echo \"spanish_notes<> $GITHUB_OUTPUT\n\n# Debug output\necho \"\"\necho \"πŸ“‹ Generated Release Notes:\"\necho \"πŸ‡ΊπŸ‡Έ English: $ENGLISH_NOTES\"\necho \"πŸ‡©πŸ‡ͺ German: $GERMAN_NOTES\"\necho \"πŸ‡§πŸ‡· Portuguese: $PORTUGUESE_NOTES\"\necho \"πŸ‡ͺπŸ‡Έ Spanish: $SPANISH_NOTES\"\n\necho \"\"\necho \"βœ… Release notes generation completed successfully\""}, "036318d98053c2484384bff0415ca3fa5e631812": {"t": 1785758175.0168273, "n": 10741, "h": "13b2296176f53727", "c": "#!/bin/bash\n\n# ==========================================\n# GENERATE RELEASE NOTES SCRIPT (BASH VERSION)\n# ==========================================\n# This script generates AI-powered release notes using DeepSeek API\n# and translates them to multiple languages using bash and curl\n#\n# Usage:\n# ./scripts/workflows/generate_release_notes.sh --type custom --changes \"change1;change2\"\n# ./scripts/workflows/generate_release_notes.sh --type default --note \"default note\"\n# ./scripts/workflows/generate_release_notes.sh --changes-file CHANGES_IN_VERSION.md\n#\n# Prefer --changes-file in CI: it reads the changelog straight from disk so the\n# text never has to be threaded back through the workflow (see SHELL-SAFETY note).\n#\n# Environment Variables:\n# DEEPSEEK_API_KEY - Required for AI generation\n\nset -e\n\n# Default values\nTYPE=\"\"\nCHANGES=\"\"\nNOTE=\"\"\nCHANGES_FILE=\"\"\n\n# Parse command line arguments\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --type)\n TYPE=\"$2\"\n shift 2\n ;;\n --changes)\n CHANGES=\"$2\"\n shift 2\n ;;\n --note)\n NOTE=\"$2\"\n shift 2\n ;;\n --changes-file)\n CHANGES_FILE=\"$2\"\n shift 2\n ;;\n *)\n echo \"Unknown parameter: $1\"\n exit 1\n ;;\n esac\ndone\n\n# ---------------------------------------------------------------------------\n# SHELL-SAFETY: read release-notes text straight from CHANGES_IN_VERSION.md.\n#\n# The workflow used to extract these strings and pass them back as\n# --changes/--note. Threading free-form text (apostrophes, \"quotes\") through a\n# workflow run: block breaks shell parsing (\"unexpected EOF while looking for\n# matching '\"). Parsing the file here keeps that text out of the workflow.\n# Do NOT reintroduce inline ${{ }} interpolation of changelog text into a\n# run: block β€” read the file (this mode) or pass via env: and read \"$VAR\".\n# ---------------------------------------------------------------------------\nparse_changes_file() {\n local file=\"$1\"\n if [ ! -f \"$file\" ]; then\n echo \"❌ Error: changes file not found: $file\"\n exit 1\n fi\n\n # Custom changes = bullet lines that appear before the \"Default\" header.\n # Match \"- \" (dash + space) so real bullets qualify but markdown comment\n # delimiters like \"-->\" or \"---\" rules never get mistaken for a bullet.\n local custom_changes\n custom_changes=$(awk '/### Default Release Notes/{exit} 1' \"$file\" | grep '^- ' || true)\n\n if [ -n \"$custom_changes\" ]; then\n TYPE=\"custom\"\n # Strip \"- \" and join bullets with ';' (generate splits back on ';').\n CHANGES=$(printf '%s\\n' \"$custom_changes\" | sed 's/^- //' | tr '\\n' ';' | sed 's/;$//')\n echo \"βœ… Using custom changes from $file\"\n else\n # No custom changes -> pick a random default note.\n local default_notes count line\n default_notes=$(awk '/### Default Release Notes/{flag=1; next} /^###/{flag=0} flag' \"$file\" | grep '^- ' || true)\n if [ -z \"$default_notes\" ]; then\n echo \"❌ Error: no release notes found in $file\"\n exit 1\n fi\n count=$(printf '%s\\n' \"$default_notes\" | grep -c '^- ')\n line=$(( RANDOM % count + 1 ))\n TYPE=\"default\"\n NOTE=$(printf '%s\\n' \"$default_notes\" | sed -n \"${line}p\" | sed 's/^- //')\n echo \"🎲 Using random default note from $file\"\n fi\n}\n\nif [ -n \"$CHANGES_FILE\" ]; then\n parse_changes_file \"$CHANGES_FILE\"\nfi\n\n# Validate required arguments\nif [ -z \"$TYPE\" ]; then\n echo \"❌ Error: --type is required (custom or default)\"\n exit 1\nfi\n\nif [ -z \"$DEEPSEEK_API_KEY\" ]; then\n echo \"❌ Error: DEEPSEEK_API_KEY environment variable is required\"\n exit 1\nfi\n\n# Load copywriting persona (voice, tone, anti-slop rules) to steer the model\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPERSONA_FILE=\"$SCRIPT_DIR/copywriting_persona.md\"\nif [ -f \"$PERSONA_FILE\" ]; then\n PERSONA_CONTENT=$(cat \"$PERSONA_FILE\")\nelse\n echo \"⚠️ Warning: copywriting_persona.md not found at $PERSONA_FILE; falling back to default system prompt\"\n PERSONA_CONTENT=\"\"\nfi\n\n# JSON-escape stdin for safe embedding in a JSON payload\njson_escape() {\n python3 -c 'import json,sys; sys.stdout.write(json.dumps(sys.stdin.read()))'\n}\n\n# Function to call DeepSeek API\ncall_deepseek_api() {\n local prompt=\"$1\"\n local max_tokens=\"${2:-150}\"\n\n local system_message=\"You are a helpful assistant that creates App Store release notes for an iOS app. Be concise, engaging, and user-friendly. Focus on benefits to users.\"\n if [ -n \"$PERSONA_CONTENT\" ]; then\n system_message=\"${system_message}\n\nFollow the voice, tone, and writing rules defined in the persona below. Pay special attention to the Anti-Slop Rules (banned phrases and patterns) and the rule against em dashes and en dashes.\n\n--- PERSONA ---\n${PERSONA_CONTENT}\n--- END PERSONA ---\"\n fi\n\n local escaped_system\n escaped_system=$(printf '%s' \"$system_message\" | json_escape)\n local escaped_user\n escaped_user=$(printf '%s' \"$prompt\" | json_escape)\n\n local json_payload=$(cat <&2\n call_deepseek_api \"$prompt\" 200\n}\n\n# Function to translate text\ntranslate_text() {\n local text=\"$1\"\n local target_language=\"$2\"\n local language_name=\"$3\"\n\n echo \"🌍 Translating to $language_name...\" >&2\n\n local prompt=\"Translate this App Store release note to $target_language:\n\n\\\"$text\\\"\n\nTranslation guidelines:\n- Convert idioms and expressions to their natural equivalents in the target language\n- Do NOT use literal word-for-word translations\n- Adapt cultural references to be appropriate for the target audience\n- Ensure it sounds completely natural to native speakers\n- Keep the same tone, style, and message intent\n- Maintain the same formatting (single paragraph, no dashes)\n\nProvide only the translation, no explanations.\"\n\n call_deepseek_api \"$prompt\" 250\n}\n\n# Generate English release notes\necho \"πŸ“ Generating AI-powered release notes...\"\nENGLISH_NOTES=$(generate_release_notes)\n\nif [ -z \"$ENGLISH_NOTES\" ]; then\n echo \"❌ Failed to generate English release notes\"\n exit 1\nfi\n\necho \"βœ… Generated English release notes\"\n\n# Generate translations\nGERMAN_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"German\" \"German\")\nPORTUGUESE_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Portuguese (Brazil)\" \"Portuguese (Brazil)\")\nSPANISH_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Spanish (Spain)\" \"Spanish (Spain)\")\n\n# Validate all translations were generated\nif [ -z \"$GERMAN_NOTES\" ] || [ -z \"$PORTUGUESE_NOTES\" ] || [ -z \"$SPANISH_NOTES\" ]; then\n echo \"❌ Failed to generate all translations\"\n exit 1\nfi\n\necho \"βœ… Generated all translations\"\n\n# Output to GitHub Actions using heredoc for multiline strings\n{\n echo \"english_notes<> $GITHUB_OUTPUT\n\n{\n echo \"german_notes<> $GITHUB_OUTPUT\n\n{\n echo \"portuguese_notes<> $GITHUB_OUTPUT\n\n{\n echo \"spanish_notes<> $GITHUB_OUTPUT\n\n# Debug output\necho \"\"\necho \"πŸ“‹ Generated Release Notes:\"\necho \"πŸ‡ΊπŸ‡Έ English: $ENGLISH_NOTES\"\necho \"πŸ‡©πŸ‡ͺ German: $GERMAN_NOTES\"\necho \"πŸ‡§πŸ‡· Portuguese: $PORTUGUESE_NOTES\"\necho \"πŸ‡ͺπŸ‡Έ Spanish: $SPANISH_NOTES\"\n\necho \"\"\necho \"βœ… Release notes generation completed successfully\""}, "44983588ca5c8c08e9e39351c2102cbe71037c0f": {"t": 1785758176.6032727, "n": 8211, "h": "0d9f792518308b4e", "c": "#!/bin/bash\n\n# ==========================================\n# GENERATE RELEASE NOTES SCRIPT (BASH VERSION)\n# ==========================================\n# This script generates AI-powered release notes using DeepSeek API\n# and translates them to multiple languages using bash and curl\n#\n# Usage:\n# ./scripts/workflows/generate_release_notes.sh --type custom --changes \"change1;change2\"\n# ./scripts/workflows/generate_release_notes.sh --type default --note \"default note\"\n#\n# Environment Variables:\n# DEEPSEEK_API_KEY - Required for AI generation\n\nset -e\n\n# Default values\nTYPE=\"\"\nCHANGES=\"\"\nNOTE=\"\"\n\n# Parse command line arguments\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --type)\n TYPE=\"$2\"\n shift 2\n ;;\n --changes)\n CHANGES=\"$2\"\n shift 2\n ;;\n --note)\n NOTE=\"$2\"\n shift 2\n ;;\n *)\n echo \"Unknown parameter: $1\"\n exit 1\n ;;\n esac\ndone\n\n# Validate required arguments\nif [ -z \"$TYPE\" ]; then\n echo \"❌ Error: --type is required (custom or default)\"\n exit 1\nfi\n\nif [ -z \"$DEEPSEEK_API_KEY\" ]; then\n echo \"❌ Error: DEEPSEEK_API_KEY environment variable is required\"\n exit 1\nfi\n\n# Load copywriting persona (voice, tone, anti-slop rules) to steer the model\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPERSONA_FILE=\"$SCRIPT_DIR/copywriting_persona.md\"\nif [ -f \"$PERSONA_FILE\" ]; then\n PERSONA_CONTENT=$(cat \"$PERSONA_FILE\")\nelse\n echo \"⚠️ Warning: copywriting_persona.md not found at $PERSONA_FILE; falling back to default system prompt\"\n PERSONA_CONTENT=\"\"\nfi\n\n# JSON-escape stdin for safe embedding in a JSON payload\njson_escape() {\n python3 -c 'import json,sys; sys.stdout.write(json.dumps(sys.stdin.read()))'\n}\n\n# Function to call DeepSeek API\ncall_deepseek_api() {\n local prompt=\"$1\"\n local max_tokens=\"${2:-150}\"\n\n local system_message=\"You are a helpful assistant that creates App Store release notes for an iOS app. Be concise, engaging, and user-friendly. Focus on benefits to users.\"\n if [ -n \"$PERSONA_CONTENT\" ]; then\n system_message=\"${system_message}\n\nFollow the voice, tone, and writing rules defined in the persona below. Pay special attention to the Anti-Slop Rules (banned phrases and patterns) and the rule against em dashes and en dashes.\n\n--- PERSONA ---\n${PERSONA_CONTENT}\n--- END PERSONA ---\"\n fi\n\n local escaped_system\n escaped_system=$(printf '%s' \"$system_message\" | json_escape)\n local escaped_user\n escaped_user=$(printf '%s' \"$prompt\" | json_escape)\n\n local json_payload=$(cat <&2\n call_deepseek_api \"$prompt\" 200\n}\n\n# Function to translate text\ntranslate_text() {\n local text=\"$1\"\n local target_language=\"$2\"\n local language_name=\"$3\"\n\n echo \"🌍 Translating to $language_name...\" >&2\n\n local prompt=\"Translate this App Store release note to $target_language:\n\n\\\"$text\\\"\n\nTranslation guidelines:\n- Convert idioms and expressions to their natural equivalents in the target language\n- Do NOT use literal word-for-word translations\n- Adapt cultural references to be appropriate for the target audience\n- Ensure it sounds completely natural to native speakers\n- Keep the same tone, style, and message intent\n- Maintain the same formatting (single paragraph, no dashes)\n\nProvide only the translation, no explanations.\"\n\n call_deepseek_api \"$prompt\" 250\n}\n\n# Generate English release notes\necho \"πŸ“ Generating AI-powered release notes...\"\nENGLISH_NOTES=$(generate_release_notes)\n\nif [ -z \"$ENGLISH_NOTES\" ]; then\n echo \"❌ Failed to generate English release notes\"\n exit 1\nfi\n\necho \"βœ… Generated English release notes\"\n\n# Generate translations\nGERMAN_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"German\" \"German\")\nPORTUGUESE_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Portuguese (Brazil)\" \"Portuguese (Brazil)\")\nSPANISH_NOTES=$(translate_text \"$ENGLISH_NOTES\" \"Spanish (Spain)\" \"Spanish (Spain)\")\n\n# Validate all translations were generated\nif [ -z \"$GERMAN_NOTES\" ] || [ -z \"$PORTUGUESE_NOTES\" ] || [ -z \"$SPANISH_NOTES\" ]; then\n echo \"❌ Failed to generate all translations\"\n exit 1\nfi\n\necho \"βœ… Generated all translations\"\n\n# Output to GitHub Actions using heredoc for multiline strings\n{\n echo \"english_notes<> $GITHUB_OUTPUT\n\n{\n echo \"german_notes<> $GITHUB_OUTPUT\n\n{\n echo \"portuguese_notes<> $GITHUB_OUTPUT\n\n{\n echo \"spanish_notes<> $GITHUB_OUTPUT\n\n# Debug output\necho \"\"\necho \"πŸ“‹ Generated Release Notes:\"\necho \"πŸ‡ΊπŸ‡Έ English: $ENGLISH_NOTES\"\necho \"πŸ‡©πŸ‡ͺ German: $GERMAN_NOTES\"\necho \"πŸ‡§πŸ‡· Portuguese: $PORTUGUESE_NOTES\"\necho \"πŸ‡ͺπŸ‡Έ Spanish: $SPANISH_NOTES\"\n\necho \"\"\necho \"βœ… Release notes generation completed successfully\""}}, ".github/workflows/trigger-new-version-process.yml": {"5897e50b1e47148e4a173108a030291af2f48ab4": {"t": 1785747054.3094199, "n": 19085, "h": "aee49c2d67170d6b", "c": "# ==========================================\n# TRIGGER NEW VERSION PROCESS WORKFLOW\n# ==========================================\n# This workflow orchestrates a complete new version release process including:\n# - Creating App Store version entry with current MARKETING_VERSION\n# - Writing AI-powered release notes (optional - can be skipped with keep_release_notes)\n# - Clearing release notes for next version (optional - skipped when keep_release_notes is true)\n# - Building and delivering to TestFlight\n# - Adding build to release and submitting for App Store review\n\nname: Trigger New Version Process\n\n# Set permissions for the workflow\npermissions:\n contents: write\n pull-requests: write\n actions: read\non:\n # ==========================================\n # MANUAL TRIGGER\n # ==========================================\n workflow_dispatch:\n inputs:\n platform:\n description: 'Platform'\n required: true\n default: 'iOS'\n type: choice\n options:\n - 'iOS'\n\n xcode_version:\n description: 'Xcode Version'\n required: false\n default: 'Xcode-26.4.1.app'\n type: choice\n options:\n - 'Xcode-26.4.1.app'\n\n test_group:\n description: 'TestFlight beta group name'\n required: false\n default: 'Reviewers'\n type: choice\n options:\n - 'Reviewers'\n\n skip_slack_posting:\n description: 'Skip Slack notifications'\n required: false\n type: boolean\n default: false\n\n keep_release_notes:\n description: 'Keep current release notes (skip writing and clearing)'\n required: false\n type: boolean\n default: false\n\n # ==========================================\n # SCHEDULED TRIGGER (DISABLED)\n # ==========================================\n schedule:\n - cron: '0 3 * * 2' # 03:00 UTC = 04:00 CET (during standard time), every Tuesday\n\n # ==========================================\n # REUSABLE WORKFLOW TRIGGER\n # ==========================================\n workflow_call:\n inputs:\n platform:\n description: 'Platform'\n required: false\n default: 'iOS'\n type: string\n\n xcode_version:\n description: 'Xcode Version'\n required: false\n default: 'Xcode-26.4.1.app'\n type: string\n\n test_group:\n description: 'TestFlight beta group name'\n required: false\n default: 'Reviewers'\n type: string\n\n skip_slack_posting:\n description: 'Skip Slack notifications'\n required: false\n default: true\n type: boolean\n\n keep_release_notes:\n description: 'Keep current release notes (skip writing and clearing)'\n required: false\n default: false\n type: boolean\n secrets:\n APP_STORE_CONNECT_KEY_ID:\n required: true\n APP_STORE_CONNECT_ISSUER_ID:\n required: true\n APP_STORE_CONNECT_KEY_CONTENT:\n required: true\n MATCH_PASSWORD:\n description: 'Match password for code signing'\n required: true\n DEEPSEEK_API_KEY:\n description: 'DeepSeek API key for AI-powered release notes generation'\n required: true\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL:\n description: 'Slack webhook for notifications (optional)'\n required: false\n\n# Environment variables\nenv:\n LANG: en_US.UTF-8\n LANGUAGE: en_US.UTF-8\n LC_ALL: en_US.UTF-8\n APP_NAME: ${{ vars.APP_NAME }}\n APP_SLUG: ${{ vars.APP_SLUG }}\n BUNDLE_ID: ${{ vars.BUNDLE_ID }}\n XCCONFIG_PATH: ${{ vars.XCCONFIG_PATH }}\n MARKETING_URL: ${{ vars.MARKETING_URL }}\n APPLE_ID: ${{ secrets.APPLE_ID }}\n APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}\n APPLE_ITC_TEAM_ID: ${{ secrets.APPLE_ITC_TEAM_ID }}\n MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}\n\njobs:\n # ==========================================\n # JOB 1: BUMP VERSION\n # ==========================================\n bump-version:\n name: Bump Version for New Release\n uses: ./.github/workflows/bump-version.yml\n with:\n version_type: current # 'current' keeps current marketing version, only increments build number\n skip_slack_posting: true\n secrets: inherit\n\n # ==========================================\n # JOB 2: CREATE APP STORE VERSION ENTRY\n # ==========================================\n create-appstore-version:\n name: Create App Store Version Entry\n needs: [bump-version]\n if: needs.bump-version.result == 'success'\n uses: ./.github/workflows/create-appstore-version.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 3: WRITE RELEASE NOTES\n # ==========================================\n write-release-notes:\n name: Write Release Notes\n needs: [create-appstore-version]\n if: needs.create-appstore-version.result == 'success' && !inputs.keep_release_notes\n uses: ./.github/workflows/write-release-notes.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 3b: UPLOAD APP STORE METADATA\n # ==========================================\n upload-metadata:\n name: Upload App Store Metadata\n needs: [create-appstore-version]\n if: needs.create-appstore-version.result == 'success'\n uses: ./.github/workflows/upload-metadata.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n BETA_CONTACT_EMAIL: ${{ secrets.BETA_CONTACT_EMAIL }}\n BETA_CONTACT_PHONE: ${{ secrets.BETA_CONTACT_PHONE }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 4: DELIVER TO TESTFLIGHT\n # ==========================================\n deliver-to-testflight:\n name: Deliver to TestFlight\n needs: [write-release-notes, create-appstore-version, upload-metadata]\n if: |\n always() &&\n needs.create-appstore-version.result == 'success' &&\n (needs.write-release-notes.result == 'success' || needs.write-release-notes.result == 'skipped') &&\n (needs.upload-metadata.result == 'success' || needs.upload-metadata.result == 'skipped')\n uses: ./.github/workflows/deliver-to-testflight.yml\n with:\n scheme: '${{ vars.APP_NAME }}'\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n test_group: ${{ inputs.test_group || 'Reviewers' }}\n release_notes: ''\n secrets:\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n SLACK_USER_ID: ${{ secrets.SLACK_USER_ID }}\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}\n BETA_CONTACT_EMAIL: ${{ secrets.BETA_CONTACT_EMAIL }}\n BETA_CONTACT_PHONE: ${{ secrets.BETA_CONTACT_PHONE }}\n BETA_DEMO_ACCOUNT_NAME: ${{ secrets.BETA_DEMO_ACCOUNT_NAME }}\n BETA_DEMO_ACCOUNT_PASSWORD: ${{ secrets.BETA_DEMO_ACCOUNT_PASSWORD }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 5: ADD BUILD TO RELEASE\n # ==========================================\n add-build-to-release:\n name: Add Build to Release\n needs: [deliver-to-testflight, create-appstore-version]\n if: needs.deliver-to-testflight.result == 'success'\n uses: ./.github/workflows/add-build-to-release.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n version: ${{ needs.create-appstore-version.outputs.version }}\n build_number: ${{ needs.deliver-to-testflight.outputs.build_number }}\n submit_for_review: true\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 6: CLEAR RELEASE NOTES\n # ==========================================\n clear-release-notes:\n name: Clear Release Notes\n needs: [add-build-to-release, write-release-notes]\n if: |\n always() &&\n (needs.add-build-to-release.result == 'success' || needs.write-release-notes.result == 'success') &&\n !inputs.keep_release_notes\n uses: ./.github/workflows/clear-release-notes.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n skip_slack_posting: true\n secrets:\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 7: SEND FINAL STATUS NOTIFICATION\n # ==========================================\n notify-final-status:\n name: Send Final Status Notification\n runs-on: macos-latest\n needs: [bump-version, create-appstore-version, write-release-notes, deliver-to-testflight, add-build-to-release, clear-release-notes]\n if: always() && !inputs.skip_slack_posting\n timeout-minutes: 5\n\n steps:\n - name: Send Slack notification\n uses: slackapi/slack-github-action@v2.1.0\n with:\n webhook: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n webhook-type: incoming-webhook\n payload: |\n {\n \"text\": \"${{ vars.APP_NAME }} iOS - New Version Process: ${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\",\n \"blocks\": [\n {\n \"type\": \"header\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"πŸš€ ${{ vars.APP_NAME }} iOS - New Version Process Summary\",\n \"emoji\": true\n }\n },\n {\n \"type\": \"section\",\n \"fields\": [\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Overall Status:*\\n${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Platform:*\\n${{ inputs.platform || 'iOS' }}\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Version:*\\n`${{ needs.create-appstore-version.outputs.version || 'Unknown' }}`\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Build:*\\n`${{ needs.deliver-to-testflight.outputs.build_number || 'Unknown' }}`\"\n }\n ]\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Process Steps:*\\nβ€’ Bump Version: ${{ needs.bump-version.result == 'success' && 'βœ…' || needs.bump-version.result == 'failure' && '❌' || '⏳' }}\\nβ€’ App Store Version: ${{ needs.create-appstore-version.result == 'success' && 'βœ…' || needs.create-appstore-version.result == 'failure' && '❌' || '⏳' }}\\nβ€’ Release Notes: ${{ inputs.keep_release_notes && '⏭️ (kept)' || needs.write-release-notes.result == 'success' && 'βœ…' || needs.write-release-notes.result == 'failure' && '❌' || needs.write-release-notes.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ Clear Notes: ${{ inputs.keep_release_notes && '⏭️ (kept)' || needs.clear-release-notes.result == 'success' && 'βœ…' || needs.clear-release-notes.result == 'failure' && '❌' || needs.clear-release-notes.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ TestFlight: ${{ needs.deliver-to-testflight.result == 'success' && 'βœ…' || needs.deliver-to-testflight.result == 'failure' && '❌' || needs.deliver-to-testflight.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ Submit for Review: ${{ needs.add-build-to-release.result == 'success' && 'βœ…' || needs.add-build-to-release.result == 'failure' && '❌' || needs.add-build-to-release.result == 'skipped' && '⏭️' || '⏳' }}\"\n }\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run #${{ github.run_number }}>\\n\\n${{ needs.add-build-to-release.result == 'success' && 'New version process completed successfully! The app has been submitted for App Store review. πŸŽ‰' || 'New version process encountered issues. Please check the workflow logs for details. 🚨' }}\"\n }\n }\n ]\n }\n\n # ==========================================\n # WORKFLOW SUMMARY\n # ==========================================\n - name: Post workflow summary\n if: always()\n run: |\n echo \"## πŸš€ New Version Process Summary\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Process Status\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Overall Status:** ${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Platform:** ${{ inputs.platform || 'iOS' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Version:** ${{ needs.create-appstore-version.outputs.version || 'Unknown' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Build Number:** ${{ needs.deliver-to-testflight.outputs.build_number || 'Unknown' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **TestFlight Group:** ${{ inputs.test_group || 'Reviewers' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Step Results\" >> $GITHUB_STEP_SUMMARY\n echo \"| Step | Status | Result |\" >> $GITHUB_STEP_SUMMARY\n echo \"|------|--------|--------|\" >> $GITHUB_STEP_SUMMARY\n echo \"| Bump Version | ${{ needs.bump-version.result == 'success' && 'βœ… Success' || needs.bump-version.result == 'failure' && '❌ Failed' || '⏳ Pending' }} | Version: ${{ needs.bump-version.outputs.new_version || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Create App Store Version | ${{ needs.create-appstore-version.result == 'success' && 'βœ… Success' || needs.create-appstore-version.result == 'failure' && '❌ Failed' || '⏳ Pending' }} | Version: ${{ needs.create-appstore-version.outputs.version || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Write Release Notes | ${{ inputs.keep_release_notes && '⏭️ Skipped (kept)' || needs.write-release-notes.result == 'success' && 'βœ… Success' || needs.write-release-notes.result == 'failure' && '❌ Failed' || needs.write-release-notes.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | ${{ inputs.keep_release_notes && 'Release notes kept from previous version' || needs.write-release-notes.outputs.status || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Clear Release Notes | ${{ inputs.keep_release_notes && '⏭️ Skipped (kept)' || needs.clear-release-notes.result == 'success' && 'βœ… Success' || needs.clear-release-notes.result == 'failure' && '❌ Failed' || needs.clear-release-notes.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | ${{ inputs.keep_release_notes && 'Kept for next version' || 'Cleared for next version' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Deliver to TestFlight | ${{ needs.deliver-to-testflight.result == 'success' && 'βœ… Success' || needs.deliver-to-testflight.result == 'failure' && '❌ Failed' || needs.deliver-to-testflight.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | Build: ${{ needs.deliver-to-testflight.outputs.build_number || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Add Build to Release | ${{ needs.add-build-to-release.result == 'success' && 'βœ… Success' || needs.add-build-to-release.result == 'failure' && '❌ Failed' || needs.add-build-to-release.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | Submitted for review |\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Next Steps\" >> $GITHUB_STEP_SUMMARY\n if [ \"${{ needs.add-build-to-release.result }}\" = \"success\" ]; then\n echo \"πŸŽ‰ **Process completed successfully!** Your app has been:\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Version bumped to ${{ needs.bump-version.outputs.new_version || 'N/A' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Version entry created in App Store Connect\" >> $GITHUB_STEP_SUMMARY\n if [ \"${{ inputs.keep_release_notes }}\" = \"true\" ]; then\n echo \"- ℹ️ Release notes kept from previous version (not regenerated)\" >> $GITHUB_STEP_SUMMARY\n else\n echo \"- βœ… Release notes written\" >> $GITHUB_STEP_SUMMARY\n fi\n echo \"- βœ… Built and delivered to TestFlight\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Submitted for App Store review\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"The app is now in the App Store review queue. You can monitor the review status in App Store Connect.\" >> $GITHUB_STEP_SUMMARY\n else\n echo \"❌ **Process incomplete.** Please check the individual step logs for error details and retry as needed.\" >> $GITHUB_STEP_SUMMARY\n fi\n"}, "44983588ca5c8c08e9e39351c2102cbe71037c0f": {"t": 1785758174.840638, "n": 19085, "h": "aee49c2d67170d6b", "c": "# ==========================================\n# TRIGGER NEW VERSION PROCESS WORKFLOW\n# ==========================================\n# This workflow orchestrates a complete new version release process including:\n# - Creating App Store version entry with current MARKETING_VERSION\n# - Writing AI-powered release notes (optional - can be skipped with keep_release_notes)\n# - Clearing release notes for next version (optional - skipped when keep_release_notes is true)\n# - Building and delivering to TestFlight\n# - Adding build to release and submitting for App Store review\n\nname: Trigger New Version Process\n\n# Set permissions for the workflow\npermissions:\n contents: write\n pull-requests: write\n actions: read\non:\n # ==========================================\n # MANUAL TRIGGER\n # ==========================================\n workflow_dispatch:\n inputs:\n platform:\n description: 'Platform'\n required: true\n default: 'iOS'\n type: choice\n options:\n - 'iOS'\n\n xcode_version:\n description: 'Xcode Version'\n required: false\n default: 'Xcode-26.4.1.app'\n type: choice\n options:\n - 'Xcode-26.4.1.app'\n\n test_group:\n description: 'TestFlight beta group name'\n required: false\n default: 'Reviewers'\n type: choice\n options:\n - 'Reviewers'\n\n skip_slack_posting:\n description: 'Skip Slack notifications'\n required: false\n type: boolean\n default: false\n\n keep_release_notes:\n description: 'Keep current release notes (skip writing and clearing)'\n required: false\n type: boolean\n default: false\n\n # ==========================================\n # SCHEDULED TRIGGER (DISABLED)\n # ==========================================\n schedule:\n - cron: '0 3 * * 2' # 03:00 UTC = 04:00 CET (during standard time), every Tuesday\n\n # ==========================================\n # REUSABLE WORKFLOW TRIGGER\n # ==========================================\n workflow_call:\n inputs:\n platform:\n description: 'Platform'\n required: false\n default: 'iOS'\n type: string\n\n xcode_version:\n description: 'Xcode Version'\n required: false\n default: 'Xcode-26.4.1.app'\n type: string\n\n test_group:\n description: 'TestFlight beta group name'\n required: false\n default: 'Reviewers'\n type: string\n\n skip_slack_posting:\n description: 'Skip Slack notifications'\n required: false\n default: true\n type: boolean\n\n keep_release_notes:\n description: 'Keep current release notes (skip writing and clearing)'\n required: false\n default: false\n type: boolean\n secrets:\n APP_STORE_CONNECT_KEY_ID:\n required: true\n APP_STORE_CONNECT_ISSUER_ID:\n required: true\n APP_STORE_CONNECT_KEY_CONTENT:\n required: true\n MATCH_PASSWORD:\n description: 'Match password for code signing'\n required: true\n DEEPSEEK_API_KEY:\n description: 'DeepSeek API key for AI-powered release notes generation'\n required: true\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL:\n description: 'Slack webhook for notifications (optional)'\n required: false\n\n# Environment variables\nenv:\n LANG: en_US.UTF-8\n LANGUAGE: en_US.UTF-8\n LC_ALL: en_US.UTF-8\n APP_NAME: ${{ vars.APP_NAME }}\n APP_SLUG: ${{ vars.APP_SLUG }}\n BUNDLE_ID: ${{ vars.BUNDLE_ID }}\n XCCONFIG_PATH: ${{ vars.XCCONFIG_PATH }}\n MARKETING_URL: ${{ vars.MARKETING_URL }}\n APPLE_ID: ${{ secrets.APPLE_ID }}\n APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}\n APPLE_ITC_TEAM_ID: ${{ secrets.APPLE_ITC_TEAM_ID }}\n MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}\n\njobs:\n # ==========================================\n # JOB 1: BUMP VERSION\n # ==========================================\n bump-version:\n name: Bump Version for New Release\n uses: ./.github/workflows/bump-version.yml\n with:\n version_type: current # 'current' keeps current marketing version, only increments build number\n skip_slack_posting: true\n secrets: inherit\n\n # ==========================================\n # JOB 2: CREATE APP STORE VERSION ENTRY\n # ==========================================\n create-appstore-version:\n name: Create App Store Version Entry\n needs: [bump-version]\n if: needs.bump-version.result == 'success'\n uses: ./.github/workflows/create-appstore-version.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 3: WRITE RELEASE NOTES\n # ==========================================\n write-release-notes:\n name: Write Release Notes\n needs: [create-appstore-version]\n if: needs.create-appstore-version.result == 'success' && !inputs.keep_release_notes\n uses: ./.github/workflows/write-release-notes.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 3b: UPLOAD APP STORE METADATA\n # ==========================================\n upload-metadata:\n name: Upload App Store Metadata\n needs: [create-appstore-version]\n if: needs.create-appstore-version.result == 'success'\n uses: ./.github/workflows/upload-metadata.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n BETA_CONTACT_EMAIL: ${{ secrets.BETA_CONTACT_EMAIL }}\n BETA_CONTACT_PHONE: ${{ secrets.BETA_CONTACT_PHONE }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 4: DELIVER TO TESTFLIGHT\n # ==========================================\n deliver-to-testflight:\n name: Deliver to TestFlight\n needs: [write-release-notes, create-appstore-version, upload-metadata]\n if: |\n always() &&\n needs.create-appstore-version.result == 'success' &&\n (needs.write-release-notes.result == 'success' || needs.write-release-notes.result == 'skipped') &&\n (needs.upload-metadata.result == 'success' || needs.upload-metadata.result == 'skipped')\n uses: ./.github/workflows/deliver-to-testflight.yml\n with:\n scheme: '${{ vars.APP_NAME }}'\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n test_group: ${{ inputs.test_group || 'Reviewers' }}\n release_notes: ''\n secrets:\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n SLACK_USER_ID: ${{ secrets.SLACK_USER_ID }}\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}\n BETA_CONTACT_EMAIL: ${{ secrets.BETA_CONTACT_EMAIL }}\n BETA_CONTACT_PHONE: ${{ secrets.BETA_CONTACT_PHONE }}\n BETA_DEMO_ACCOUNT_NAME: ${{ secrets.BETA_DEMO_ACCOUNT_NAME }}\n BETA_DEMO_ACCOUNT_PASSWORD: ${{ secrets.BETA_DEMO_ACCOUNT_PASSWORD }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 5: ADD BUILD TO RELEASE\n # ==========================================\n add-build-to-release:\n name: Add Build to Release\n needs: [deliver-to-testflight, create-appstore-version]\n if: needs.deliver-to-testflight.result == 'success'\n uses: ./.github/workflows/add-build-to-release.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n version: ${{ needs.create-appstore-version.outputs.version }}\n build_number: ${{ needs.deliver-to-testflight.outputs.build_number }}\n submit_for_review: true\n xcode_version: ${{ inputs.xcode_version || 'Xcode-26.4.1.app' }}\n skip_slack_posting: true\n secrets:\n APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}\n APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}\n APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }}\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n\n # ==========================================\n # JOB 6: CLEAR RELEASE NOTES\n # ==========================================\n clear-release-notes:\n name: Clear Release Notes\n needs: [add-build-to-release, write-release-notes]\n if: |\n always() &&\n (needs.add-build-to-release.result == 'success' || needs.write-release-notes.result == 'success') &&\n !inputs.keep_release_notes\n uses: ./.github/workflows/clear-release-notes.yml\n with:\n platform: ${{ inputs.platform || 'iOS' }}\n skip_slack_posting: true\n secrets:\n SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}\n GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}\n\n # ==========================================\n # JOB 7: SEND FINAL STATUS NOTIFICATION\n # ==========================================\n notify-final-status:\n name: Send Final Status Notification\n runs-on: macos-latest\n needs: [bump-version, create-appstore-version, write-release-notes, deliver-to-testflight, add-build-to-release, clear-release-notes]\n if: always() && !inputs.skip_slack_posting\n timeout-minutes: 5\n\n steps:\n - name: Send Slack notification\n uses: slackapi/slack-github-action@v2.1.0\n with:\n webhook: ${{ secrets.SLACK_WEBHOOK_GITHUB_EVENTS_CHANNEL }}\n webhook-type: incoming-webhook\n payload: |\n {\n \"text\": \"${{ vars.APP_NAME }} iOS - New Version Process: ${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\",\n \"blocks\": [\n {\n \"type\": \"header\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"πŸš€ ${{ vars.APP_NAME }} iOS - New Version Process Summary\",\n \"emoji\": true\n }\n },\n {\n \"type\": \"section\",\n \"fields\": [\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Overall Status:*\\n${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Platform:*\\n${{ inputs.platform || 'iOS' }}\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Version:*\\n`${{ needs.create-appstore-version.outputs.version || 'Unknown' }}`\"\n },\n {\n \"type\": \"mrkdwn\",\n \"text\": \"*Build:*\\n`${{ needs.deliver-to-testflight.outputs.build_number || 'Unknown' }}`\"\n }\n ]\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Process Steps:*\\nβ€’ Bump Version: ${{ needs.bump-version.result == 'success' && 'βœ…' || needs.bump-version.result == 'failure' && '❌' || '⏳' }}\\nβ€’ App Store Version: ${{ needs.create-appstore-version.result == 'success' && 'βœ…' || needs.create-appstore-version.result == 'failure' && '❌' || '⏳' }}\\nβ€’ Release Notes: ${{ inputs.keep_release_notes && '⏭️ (kept)' || needs.write-release-notes.result == 'success' && 'βœ…' || needs.write-release-notes.result == 'failure' && '❌' || needs.write-release-notes.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ Clear Notes: ${{ inputs.keep_release_notes && '⏭️ (kept)' || needs.clear-release-notes.result == 'success' && 'βœ…' || needs.clear-release-notes.result == 'failure' && '❌' || needs.clear-release-notes.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ TestFlight: ${{ needs.deliver-to-testflight.result == 'success' && 'βœ…' || needs.deliver-to-testflight.result == 'failure' && '❌' || needs.deliver-to-testflight.result == 'skipped' && '⏭️' || '⏳' }}\\nβ€’ Submit for Review: ${{ needs.add-build-to-release.result == 'success' && 'βœ…' || needs.add-build-to-release.result == 'failure' && '❌' || needs.add-build-to-release.result == 'skipped' && '⏭️' || '⏳' }}\"\n }\n },\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*Workflow:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run #${{ github.run_number }}>\\n\\n${{ needs.add-build-to-release.result == 'success' && 'New version process completed successfully! The app has been submitted for App Store review. πŸŽ‰' || 'New version process encountered issues. Please check the workflow logs for details. 🚨' }}\"\n }\n }\n ]\n }\n\n # ==========================================\n # WORKFLOW SUMMARY\n # ==========================================\n - name: Post workflow summary\n if: always()\n run: |\n echo \"## πŸš€ New Version Process Summary\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Process Status\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Overall Status:** ${{ needs.add-build-to-release.result == 'success' && 'βœ… Completed Successfully' || '❌ Failed or Incomplete' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Platform:** ${{ inputs.platform || 'iOS' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Version:** ${{ needs.create-appstore-version.outputs.version || 'Unknown' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **Build Number:** ${{ needs.deliver-to-testflight.outputs.build_number || 'Unknown' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- **TestFlight Group:** ${{ inputs.test_group || 'Reviewers' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Step Results\" >> $GITHUB_STEP_SUMMARY\n echo \"| Step | Status | Result |\" >> $GITHUB_STEP_SUMMARY\n echo \"|------|--------|--------|\" >> $GITHUB_STEP_SUMMARY\n echo \"| Bump Version | ${{ needs.bump-version.result == 'success' && 'βœ… Success' || needs.bump-version.result == 'failure' && '❌ Failed' || '⏳ Pending' }} | Version: ${{ needs.bump-version.outputs.new_version || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Create App Store Version | ${{ needs.create-appstore-version.result == 'success' && 'βœ… Success' || needs.create-appstore-version.result == 'failure' && '❌ Failed' || '⏳ Pending' }} | Version: ${{ needs.create-appstore-version.outputs.version || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Write Release Notes | ${{ inputs.keep_release_notes && '⏭️ Skipped (kept)' || needs.write-release-notes.result == 'success' && 'βœ… Success' || needs.write-release-notes.result == 'failure' && '❌ Failed' || needs.write-release-notes.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | ${{ inputs.keep_release_notes && 'Release notes kept from previous version' || needs.write-release-notes.outputs.status || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Clear Release Notes | ${{ inputs.keep_release_notes && '⏭️ Skipped (kept)' || needs.clear-release-notes.result == 'success' && 'βœ… Success' || needs.clear-release-notes.result == 'failure' && '❌ Failed' || needs.clear-release-notes.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | ${{ inputs.keep_release_notes && 'Kept for next version' || 'Cleared for next version' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Deliver to TestFlight | ${{ needs.deliver-to-testflight.result == 'success' && 'βœ… Success' || needs.deliver-to-testflight.result == 'failure' && '❌ Failed' || needs.deliver-to-testflight.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | Build: ${{ needs.deliver-to-testflight.outputs.build_number || 'N/A' }} |\" >> $GITHUB_STEP_SUMMARY\n echo \"| Add Build to Release | ${{ needs.add-build-to-release.result == 'success' && 'βœ… Success' || needs.add-build-to-release.result == 'failure' && '❌ Failed' || needs.add-build-to-release.result == 'skipped' && '⏭️ Skipped' || '⏳ Pending' }} | Submitted for review |\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"### Next Steps\" >> $GITHUB_STEP_SUMMARY\n if [ \"${{ needs.add-build-to-release.result }}\" = \"success\" ]; then\n echo \"πŸŽ‰ **Process completed successfully!** Your app has been:\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Version bumped to ${{ needs.bump-version.outputs.new_version || 'N/A' }}\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Version entry created in App Store Connect\" >> $GITHUB_STEP_SUMMARY\n if [ \"${{ inputs.keep_release_notes }}\" = \"true\" ]; then\n echo \"- ℹ️ Release notes kept from previous version (not regenerated)\" >> $GITHUB_STEP_SUMMARY\n else\n echo \"- βœ… Release notes written\" >> $GITHUB_STEP_SUMMARY\n fi\n echo \"- βœ… Built and delivered to TestFlight\" >> $GITHUB_STEP_SUMMARY\n echo \"- βœ… Submitted for App Store review\" >> $GITHUB_STEP_SUMMARY\n echo \"\" >> $GITHUB_STEP_SUMMARY\n echo \"The app is now in the App Store review queue. You can monitor the review status in App Store Connect.\" >> $GITHUB_STEP_SUMMARY\n else\n echo \"❌ **Process incomplete.** Please check the individual step logs for error details and retry as needed.\" >> $GITHUB_STEP_SUMMARY\n fi\n"}}}}