diff --git a/.github/actions/jira-transition-tickets/README.md b/.github/actions/jira-transition-tickets/README.md new file mode 100644 index 0000000..6de0a4e --- /dev/null +++ b/.github/actions/jira-transition-tickets/README.md @@ -0,0 +1,105 @@ +# JIRA Transition Tickets + +A GitHub Action that automatically transitions JIRA tickets to a specified status based on merged branch names. + +## Overview + +This action helps automate JIRA ticket workflows by: +- Extracting JIRA ticket keys from branch names (e.g., `feature/ABC-123-add-feature`) +- Transitioning matched tickets to a target status (e.g., "Done", "In QA", "Ready for Testing") + +This action was designed to work with `merged_branches` output of [universal-detect-changes-and-generate-changelog](../universal-detect-changes-and-generate-changelog) action. + +## Inputs + +### `jira_context` (required) + +A base64-encoded JSON string containing JIRA authentication credentials and configuration. + +**Structure:** +```json +{ + "cloud_id": "your-cloud-id", + "user_email": "your-bot@serviceaccount.atlassian.com", + "api_token": "YourJiraApiToken" +} +``` + +**How to obtain Cloud ID:** + +Navigate to [https://.atlassian.net/_edge/tenant_info](https://.atlassian.net/_edge/tenant_info) + +**How to encode:** +```bash +echo -n '{"cloud_id":"your-cloud-id","user_email":"bot@example.com","api_token":"token"}' | base64 +``` + +**GitHub Secrets:** +Store the base64-encoded string in a GitHub secret (e.g., `JIRA_CONTEXT`) for secure usage. + +### `transition` (required) + +The name of the JIRA transition to execute. This must match the exact transition name in your JIRA workflow. + +**Examples:** `"Done"`, `"In QA"`, `"Ready for Testing"`, `"Closed"` + +### `merged_branches` (required) + +A comma-separated string of branch names from which to extract JIRA ticket keys. + +The action extracts keys matching the pattern `[A-Z]+-[0-9]+` from each branch name. + +**Example:** `"feature/ABC-123-login,bugfix/XYZ-456-fix-crash"` + +## How It Works + +1. **Extract JIRA Keys:** Parses branch names to extract ticket keys (e.g., `ABC-123`) +2. **Get Available Transitions:** For each issue key, fetches available transitions from JIRA API +3. **Find Target Transition:** Matches the target status name to find the corresponding transition ID +4. **Perform Transition:** Executes the transition for each issue to move it to the target status + +## Usage Examples + +### Example 1: Transition tickets from merged branches + +```yaml +- name: Transition JIRA tickets + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: "Ready for Testing" + merged_branches: "feature/PROJ-123-new-feature,bugfix/PROJ-456-bug-fix" +``` + +### Example 2: Transition tickets from dynamic branch list + +```yaml +- name: Transition tickets + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: "Ready for Testing" + merged_branches: ${{ steps.get_branches.outputs.branches }} +``` + +### Example 3: In a reusable workflow + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build app + run: ./build.sh + + - name: Transition JIRA tickets on success + if: success() + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: "Ready for Testing" + merged_branches: ${{ github.head_ref }} +``` diff --git a/.github/actions/jira-transition-tickets/action.yml b/.github/actions/jira-transition-tickets/action.yml new file mode 100644 index 0000000..b2122e7 --- /dev/null +++ b/.github/actions/jira-transition-tickets/action.yml @@ -0,0 +1,40 @@ +name: 'JIRA Transition Tickets' +description: 'Finds and transitions JIRA tickets based on branch names.' + +inputs: + jira_context: + description: 'A base64-encoded string of Jira context object. See README for required structure.' + required: true + transition: + description: 'The name of the transition to transition the JIRA tickets.' + required: true + merged_branches: + description: 'A comma-separated string of merged branch names.' + required: true + +runs: + using: "composite" + steps: + - name: Make scripts executable + shell: bash + working-directory: ${{ github.action_path }} + run: | + chmod +x ./scripts/extract-issue-keys.sh + chmod +x ./scripts/transition-issues.sh + + - name: Extract Issue Keys + id: extract + shell: bash + working-directory: ${{ github.action_path }} + run: | + ./scripts/extract-issue-keys.sh \ + "${{ inputs.merged_branches }}" + + - name: Transition JIRA Tickets + shell: bash + working-directory: ${{ github.action_path }} + run: | + ./scripts/transition-issues.sh \ + "${{ inputs.jira_context }}" \ + "${{ inputs.transition }}" \ + "${{ steps.extract.outputs.issue_keys }}" diff --git a/.github/actions/jira-transition-tickets/scripts/extract-issue-keys.sh b/.github/actions/jira-transition-tickets/scripts/extract-issue-keys.sh new file mode 100755 index 0000000..8c8c33b --- /dev/null +++ b/.github/actions/jira-transition-tickets/scripts/extract-issue-keys.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +MERGED_BRANCHES="$1" + +# Extract JIRA keys from branches +JIRA_KEYS=() +if [[ -n "$MERGED_BRANCHES" ]]; then + # Prevents globbing and word splitting issues + IFS=',' read -ra BRANCHES <<< "$MERGED_BRANCHES" + for branch in "${BRANCHES[@]}"; do + # Trim leading/trailing whitespace from branch name + branch=$(echo "$branch" | xargs) + while IFS= read -r key; do + JIRA_KEYS+=("$key") + done < <(echo "$branch" | grep -oE '[A-Z0-9]+-[0-9]+') + done +fi + +# Remove duplicate keys and create a space-separated string +UNIQUE_JIRA_KEYS_STR=$(echo "${JIRA_KEYS[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ' | xargs) + +# Build issue keys list +ISSUE_KEYS="" +if [[ -n "$UNIQUE_JIRA_KEYS_STR" ]]; then + ISSUE_KEYS="${UNIQUE_JIRA_KEYS_STR// /,}" +fi + +# Set the output for the GitHub Action step +echo "issue_keys=$ISSUE_KEYS" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/jira-transition-tickets/scripts/transition-issues.sh b/.github/actions/jira-transition-tickets/scripts/transition-issues.sh new file mode 100755 index 0000000..7d2e02a --- /dev/null +++ b/.github/actions/jira-transition-tickets/scripts/transition-issues.sh @@ -0,0 +1,94 @@ +#!/bin/bash +set -e + +JIRA_CONTEXT="$1" +TRANSITION_NAME="$2" +ISSUE_KEYS="$3" + +# Decode and parse JIRA_CONTEXT +JIRA_CONTEXT_JSON=$(echo "$JIRA_CONTEXT" | base64 --decode) +JIRA_CLOUD_ID=$(echo "$JIRA_CONTEXT_JSON" | jq -r '.cloud_id') +JIRA_USER_EMAIL=$(echo "$JIRA_CONTEXT_JSON" | jq -r '.user_email') +JIRA_API_TOKEN=$(echo "$JIRA_CONTEXT_JSON" | jq -r '.api_token') +JIRA_BASE_URL="https://api.atlassian.com/ex/jira/${JIRA_CLOUD_ID}" + +if [[ -z "$ISSUE_KEYS" ]]; then + echo "No issue keys provided. Skipping transition." + exit 0 +fi + +echo "Processing issue keys: $ISSUE_KEYS" + +# Split comma-separated issue keys +IFS=',' read -ra KEYS <<< "$ISSUE_KEYS" + +# Loop through each issue key and transition it +for issue_key in "${KEYS[@]}"; do + # Trim whitespace + issue_key=$(echo "$issue_key" | xargs) + + if [[ -z "$issue_key" ]]; then + continue + fi + + echo "Processing issue: $issue_key" + + # Get available transitions for this issue + TRANSITIONS_URL="${JIRA_BASE_URL}/rest/api/3/issue/${issue_key}/transitions" + + TRANSITIONS_FULL_RESPONSE=$(curl -s -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -X GET -H "Content-Type: application/json" \ + -w '\n%{http_code}' \ + "$TRANSITIONS_URL") + + # Extract HTTP status code (last line) and response body (everything else) + TRANSITIONS_HTTP_CODE=$(echo "$TRANSITIONS_FULL_RESPONSE" | tail -n1) + TRANSITIONS_RESPONSE=$(echo "$TRANSITIONS_FULL_RESPONSE" | sed '$d') + + # Check if the HTTP status code indicates success (2xx) + if [[ ! "$TRANSITIONS_HTTP_CODE" =~ ^2[0-9]{2}$ ]]; then + echo "Error getting transitions for issue $issue_key: HTTP $TRANSITIONS_HTTP_CODE" + if [[ -n "$TRANSITIONS_RESPONSE" ]]; then + echo "$TRANSITIONS_RESPONSE" | jq . 2>/dev/null || echo "$TRANSITIONS_RESPONSE" + fi + continue + fi + + # Find the transition ID by matching the transition name (case-insensitive) + TRANSITION_ID=$(echo "$TRANSITIONS_RESPONSE" | \ + jq -r --arg name "$TRANSITION_NAME" \ + '.transitions[] | select(.name | ascii_downcase == ($name | ascii_downcase)) | .id') + + if [[ -z "$TRANSITION_ID" || "$TRANSITION_ID" == "null" ]]; then + echo "Warning: Could not find transition '$TRANSITION_NAME' for issue $issue_key. It might already be in the target status or the transition is not available. Skipping." + continue + fi + + echo "Found transition ID '$TRANSITION_ID' for issue $issue_key. Attempting to transition to '$TRANSITION_NAME'." + + # Perform the transition + TRANSITION_URL="${JIRA_BASE_URL}/rest/api/3/issue/${issue_key}/transitions" + + TRANSITION_FULL_RESULT=$(curl -s -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + -X POST \ + -H "Content-Type: application/json" \ + -w '\n%{http_code}' \ + --data "{\"transition\": {\"id\": \"$TRANSITION_ID\"}}" \ + "$TRANSITION_URL") + + # Extract HTTP status code (last line) and response body (everything else) + TRANSITION_HTTP_CODE=$(echo "$TRANSITION_FULL_RESULT" | tail -n1) + TRANSITION_RESULT=$(echo "$TRANSITION_FULL_RESULT" | sed '$d') + + # Check if the HTTP status code indicates success (2xx) + if [[ ! "$TRANSITION_HTTP_CODE" =~ ^2[0-9]{2}$ ]]; then + echo "Error transitioning issue $issue_key: HTTP $TRANSITION_HTTP_CODE" + if [[ -n "$TRANSITION_RESULT" ]]; then + echo "$TRANSITION_RESULT" | jq . 2>/dev/null || echo "$TRANSITION_RESULT" + fi + else + echo "Successfully transitioned issue $issue_key to '$TRANSITION_NAME'." + fi +done + +echo "JIRA transition process completed." diff --git a/.github/actions/jira-transition-tickets/test/test_extract-issue-keys.bats b/.github/actions/jira-transition-tickets/test/test_extract-issue-keys.bats new file mode 100644 index 0000000..876b4d8 --- /dev/null +++ b/.github/actions/jira-transition-tickets/test/test_extract-issue-keys.bats @@ -0,0 +1,185 @@ +#!/usr/bin/env bats + +load 'test_helper' + +# Setup for each test +setup() { + setup_github_output +} + +# Teardown for each test +teardown() { + teardown_github_output +} + +@test "extract-issue-keys: handles empty input" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "" ] +} + +@test "extract-issue-keys: extracts single JIRA key from branch" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-add-feature" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: extracts single JIRA key from branch with just issue key" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: extracts multiple JIRA keys from single branch" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-PROJ-456-combine" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123,PROJ-456" ] +} + +@test "extract-issue-keys: extracts keys from multiple branches" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-feature,bugfix/PROJ-456-fix" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123,PROJ-456" ] +} + +@test "extract-issue-keys: removes duplicate JIRA keys" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-feature,bugfix/PROJ-123-fix" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: handles branch without JIRA key" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/some-feature" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "" ] +} + +@test "extract-issue-keys: handles mixed branches (with and without keys)" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-feature,hotfix/some-fix,bugfix/PROJ-456-bug" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123,PROJ-456" ] +} + +@test "extract-issue-keys: handles whitespace in branch names" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" " feature/PROJ-123-feature , bugfix/PROJ-456-fix " + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123,PROJ-456" ] +} + +@test "extract-issue-keys: extracts keys with different project prefixes" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/ABC-123-DEF-456-GHI-789" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "ABC-123,DEF-456,GHI-789" ] +} + +@test "extract-issue-keys: extracts JIRA key at start of branch name" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "PROJ-123-feature-branch" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: extracts JIRA key in middle of branch name" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature-PROJ-123-branch" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: extracts JIRA key at end of branch name" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature-branch-PROJ-123" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: ignores lowercase project codes" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/proj-123-test" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "" ] +} + +@test "extract-issue-keys: handles special characters in branch names" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123_with_underscores,bugfix/PROJ-456-with-dashes" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123,PROJ-456" ] +} + +@test "extract-issue-keys: handles multiple branches with sorting" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "PROJ-3,PROJ-1,PROJ-2" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-1,PROJ-2,PROJ-3" ] +} + +@test "extract-issue-keys: handles duplicate keys in same branch" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-and-PROJ-123-again" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: handles complex multi-branch scenario with duplicates" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123-ABC-456,bugfix/PROJ-123-DEF-789,hotfix/ABC-456" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "ABC-456,DEF-789,PROJ-123" ] +} + +@test "extract-issue-keys: handles JIRA keys with large numbers" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-999999-test" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-999999" ] +} + +@test "extract-issue-keys: handles JIRA keys with short project codes" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/AB-123-test" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "AB-123" ] +} + +@test "extract-issue-keys: handles multiple commas in input" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/PROJ-123,,,bugfix/PROJ-456" + + [ "$status" -eq 0 ] + result="$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" + # Should contain both keys + echo "$result" | grep -q "PROJ-123" + echo "$result" | grep -q "PROJ-456" +} + +@test "extract-issue-keys: handles branch with slash in name" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/team/PROJ-123-description" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ-123" ] +} + +@test "extract-issue-keys: handles number in project identifier" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/team/PROJ25-123-description" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ25-123" ] +} + + +@test "extract-issue-keys: handles multiple issue keys with number in project identifier" { + run "$BATS_TEST_DIRNAME/../scripts/extract-issue-keys.sh" "feature/team/PROJ25-123-description,feature/PROJ25-456-description" + + [ "$status" -eq 0 ] + [ "$(grep '^issue_keys=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "PROJ25-123,PROJ25-456" ] +} diff --git a/.github/actions/jira-transition-tickets/test/test_helper.bash b/.github/actions/jira-transition-tickets/test/test_helper.bash new file mode 100644 index 0000000..5b90457 --- /dev/null +++ b/.github/actions/jira-transition-tickets/test/test_helper.bash @@ -0,0 +1,119 @@ +#!/usr/bin/env bash + +# Test helper functions for BATS tests + +# Setup GITHUB_OUTPUT for tests that need it +setup_github_output() { + export GITHUB_OUTPUT=$(mktemp) +} + +# Clean up GITHUB_OUTPUT +teardown_github_output() { + rm -f "$GITHUB_OUTPUT" +} + +# Mock curl for transition-issues.sh tests +# Usage: setup_curl_mock +# Sets up curl mocking by creating a mock curl function +setup_curl_mock() { + export CURL_MOCK_RESPONSES_DIR=$(mktemp -d) + export PATH="$BATS_TEST_DIRNAME/mocks:$PATH" + + # Create mock curl script + mkdir -p "$BATS_TEST_DIRNAME/mocks" + cat > "$BATS_TEST_DIRNAME/mocks/curl" << 'EOF' +#!/usr/bin/env bash +# Mock curl for testing + +# Extract the URL and method from arguments +URL="" +METHOD="GET" +WRITE_OUT="" +for arg in "$@"; do + if [[ "$arg" == http* ]]; then + URL="$arg" + fi + if [[ "$prev_arg" == "-X" ]]; then + METHOD="$arg" + fi + if [[ "$prev_arg" == "-w" ]]; then + WRITE_OUT="$arg" + fi + prev_arg="$arg" +done + +# Determine response and status code based on URL and method +if [[ "$URL" == *"/transitions"* ]] && [[ "$METHOD" == "GET" ]]; then + # Return transitions list + if [[ -f "$CURL_MOCK_RESPONSES_DIR/get_transitions_status_code.txt" ]]; then + STATUS_CODE=$(cat "$CURL_MOCK_RESPONSES_DIR/get_transitions_status_code.txt") + else + STATUS_CODE="200" + fi + + if [[ -f "$CURL_MOCK_RESPONSES_DIR/get_transitions_response.json" ]]; then + cat "$CURL_MOCK_RESPONSES_DIR/get_transitions_response.json" + else + echo '{"transitions":[{"id":"31","name":"Done"},{"id":"21","name":"In Progress"}]}' + fi +elif [[ "$URL" == *"/transitions"* ]] && [[ "$METHOD" == "POST" ]]; then + # Return transition result + if [[ -f "$CURL_MOCK_RESPONSES_DIR/post_transition_status_code.txt" ]]; then + STATUS_CODE=$(cat "$CURL_MOCK_RESPONSES_DIR/post_transition_status_code.txt") + else + STATUS_CODE="204" + fi + + if [[ -f "$CURL_MOCK_RESPONSES_DIR/post_transition_response.json" ]]; then + cat "$CURL_MOCK_RESPONSES_DIR/post_transition_response.json" + else + echo '' + fi +else + STATUS_CODE="404" + echo '{"errorMessages":["Unknown endpoint"]}' +fi + +# Output status code if -w flag was provided +if [[ -n "$WRITE_OUT" ]]; then + echo -n "$STATUS_CODE" +fi +EOF + chmod +x "$BATS_TEST_DIRNAME/mocks/curl" +} + +# Clean up curl mock +teardown_curl_mock() { + rm -rf "$CURL_MOCK_RESPONSES_DIR" + rm -f "$BATS_TEST_DIRNAME/mocks/curl" + rmdir "$BATS_TEST_DIRNAME/mocks" 2>/dev/null || true +} + +# Set a specific mock response for GET transitions +# Usage: set_mock_get_transitions_response '{"transitions":[...]}' [status_code] +set_mock_get_transitions_response() { + echo "$1" > "$CURL_MOCK_RESPONSES_DIR/get_transitions_response.json" + if [[ -n "$2" ]]; then + echo "$2" > "$CURL_MOCK_RESPONSES_DIR/get_transitions_status_code.txt" + else + echo "200" > "$CURL_MOCK_RESPONSES_DIR/get_transitions_status_code.txt" + fi +} + +# Set a specific mock response for POST transition +# Usage: set_mock_post_transition_response '' [status_code] +set_mock_post_transition_response() { + echo "$1" > "$CURL_MOCK_RESPONSES_DIR/post_transition_response.json" + if [[ -n "$2" ]]; then + echo "$2" > "$CURL_MOCK_RESPONSES_DIR/post_transition_status_code.txt" + else + echo "204" > "$CURL_MOCK_RESPONSES_DIR/post_transition_status_code.txt" + fi +} + +# Create base64 encoded JIRA context for testing +# Usage: create_test_jira_context +create_test_jira_context() { + local jira_context_json='{"cloud_id":"test-cloud-id-123","user_email":"test@example.com","api_token":"test-token-123"}' + echo "$jira_context_json" | base64 +} diff --git a/.github/actions/jira-transition-tickets/test/test_integration.sh b/.github/actions/jira-transition-tickets/test/test_integration.sh new file mode 100755 index 0000000..8e5f2eb --- /dev/null +++ b/.github/actions/jira-transition-tickets/test/test_integration.sh @@ -0,0 +1,161 @@ +#!/bin/bash +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}=== JIRA Transition Integration Test ===${NC}\n" + +# ============================================ +# Script Arguments +# ============================================ + +TRANSITION_NAME="$1" +MERGED_BRANCHES="$2" + +# ============================================ +# Environment Variables (JIRA Credentials) +# ============================================ + +# Option 1: Provide base64-encoded JIRA context directly +JIRA_CONTEXT="${JIRA_CONTEXT:-}" + +# Option 2: Provide individual credentials (will be encoded automatically) +JIRA_CLOUD_ID="${JIRA_CLOUD_ID:-}" +JIRA_USER_EMAIL="${JIRA_USER_EMAIL:-}" +JIRA_API_TOKEN="${JIRA_API_TOKEN:-}" + +# ============================================ +# Validation +# ============================================ + +# Check required inputs +MISSING_PARAMS=() + +if [[ -z "$TRANSITION_NAME" ]]; then + MISSING_PARAMS+=("TRANSITION_NAME") +fi + +if [[ -z "$MERGED_BRANCHES" ]]; then + MISSING_PARAMS+=("MERGED_BRANCHES") +fi + +if [[ -z "$JIRA_CONTEXT" ]]; then + # No pre-encoded context, check for individual credentials + if [[ -z "$JIRA_CLOUD_ID" ]] || [[ -z "$JIRA_USER_EMAIL" ]] || [[ -z "$JIRA_API_TOKEN" ]]; then + MISSING_PARAMS+=("JIRA credentials") + fi + USE_PRE_ENCODED=false +else + USE_PRE_ENCODED=true +fi + +if [[ ${#MISSING_PARAMS[@]} -gt 0 ]]; then + echo -e "${RED}Error: Missing required parameters: ${MISSING_PARAMS[*]}${NC}" + echo "" + echo "Usage:" + echo " $0 " + echo "" + echo "Example:" + echo " $0 'Done' 'feature/ABC-123,feature/XYZ-456'" + echo "" + echo "JIRA credentials must be set as environment variables (choose one option):" + echo "" + echo "Option 1 - Provide base64-encoded JIRA context:" + echo " export JIRA_CONTEXT=''" + echo "" + echo "Option 2 - Provide individual credentials:" + echo " export JIRA_CLOUD_ID='your-cloud-id'" + echo " export JIRA_USER_EMAIL='your-email@example.com'" + echo " export JIRA_API_TOKEN='your-api-token'" + echo "" + exit 1 +fi + +echo -e "${YELLOW}Configuration:${NC}" +if [[ "$USE_PRE_ENCODED" == "true" ]]; then + echo " JIRA Context: " +else + echo " Cloud ID: $JIRA_CLOUD_ID" + echo " User Email: $JIRA_USER_EMAIL" +fi +echo " Transition: $TRANSITION_NAME" +echo " Merged Branches: $MERGED_BRANCHES" +echo "" + +# ============================================ +# Step 1: Run extract-issue-keys.sh +# ============================================ + +echo -e "${BLUE}Step 1: Extracting issue keys from branches${NC}" + +# Create a temporary file to simulate GITHUB_OUTPUT +TEMP_OUTPUT=$(mktemp) +export GITHUB_OUTPUT="$TEMP_OUTPUT" + +# Run the extraction script +../scripts/extract-issue-keys.sh "$MERGED_BRANCHES" + +# Read the output +if [[ ! -f "$TEMP_OUTPUT" ]]; then + echo -e "${RED}Error: extract-issue-keys.sh did not create output file${NC}" + exit 1 +fi + +ISSUE_KEYS=$(grep "issue_keys=" "$TEMP_OUTPUT" | cut -d'=' -f2-) + +echo -e "${GREEN}โœ“ Extracted issue keys: ${ISSUE_KEYS}${NC}" +echo "" + +if [[ -z "$ISSUE_KEYS" ]]; then + echo -e "${YELLOW}Warning: No issue keys found in branches. Nothing to transition.${NC}" + rm -f "$TEMP_OUTPUT" + exit 0 +fi + +# ============================================ +# Step 2: Prepare JIRA context +# ============================================ + +echo -e "${BLUE}Step 2: Preparing JIRA context${NC}" + +if [[ "$USE_PRE_ENCODED" == "true" ]]; then + # Use the pre-encoded context + JIRA_CONTEXT_BASE64="$JIRA_CONTEXT" + echo -e "${GREEN}โœ“ Using pre-encoded JIRA context${NC}" +else + # Create the JIRA context JSON from individual credentials + JIRA_CONTEXT_JSON=$(jq -n \ + --arg cloud_id "$JIRA_CLOUD_ID" \ + --arg user_email "$JIRA_USER_EMAIL" \ + --arg api_token "$JIRA_API_TOKEN" \ + '{cloud_id: $cloud_id, user_email: $user_email, api_token: $api_token}') + + # Base64 encode it + JIRA_CONTEXT_BASE64=$(echo "$JIRA_CONTEXT_JSON" | base64) + echo -e "${GREEN}โœ“ JIRA context created and encoded${NC}" +fi +echo "" + +# ============================================ +# Step 3: Run transition-issues.sh +# ============================================ + +echo -e "${BLUE}Step 3: Transitioning JIRA issues${NC}" +echo "" + +# Run the transition script +../scripts/transition-issues.sh \ + "$JIRA_CONTEXT_BASE64" \ + "$TRANSITION_NAME" \ + "$ISSUE_KEYS" + +echo "" +echo -e "${GREEN}=== Integration test completed ===${NC}" + +# Cleanup +rm -f "$TEMP_OUTPUT" diff --git a/.github/actions/jira-transition-tickets/test/test_transition-issues.bats b/.github/actions/jira-transition-tickets/test/test_transition-issues.bats new file mode 100644 index 0000000..e6fb86c --- /dev/null +++ b/.github/actions/jira-transition-tickets/test/test_transition-issues.bats @@ -0,0 +1,330 @@ +#!/usr/bin/env bats + +load 'test_helper' + +# Setup for each test +setup() { + setup_github_output + setup_curl_mock + JIRA_CONTEXT=$(create_test_jira_context) +} + +# Teardown for each test +teardown() { + teardown_github_output + teardown_curl_mock +} + +@test "transition-issues: handles empty issue keys" { + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "" + + [ "$status" -eq 0 ] + [[ "$output" == *"No issue keys provided"* ]] + [[ "$output" == *"Skipping transition"* ]] +} + +@test "transition-issues: successfully transitions single issue" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"},{"id":"21","name":"In Progress"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue: PROJ-123"* ]] + [[ "$output" == *"Found transition ID '31'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'Done'"* ]] +} + +@test "transition-issues: successfully transitions multiple issues" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123,PROJ-456" + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue: PROJ-123"* ]] + [[ "$output" == *"Processing issue: PROJ-456"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-456"* ]] +} + +@test "transition-issues: handles whitespace in issue keys" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" " PROJ-123 , PROJ-456 " + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue: PROJ-123"* ]] + [[ "$output" == *"Processing issue: PROJ-456"* ]] +} + +@test "transition-issues: skips when transition is not found" { + set_mock_get_transitions_response '{"transitions":[{"id":"21","name":"In Progress"}]}' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Warning: Could not find transition 'Done'"* ]] + [[ "$output" == *"Skipping"* ]] +} + +@test "transition-issues: handles 404 error when getting transitions" { + set_mock_get_transitions_response '{"errorMessages":["Issue does not exist"]}' "404" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-999" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error getting transitions for issue PROJ-999"* ]] + [[ "$output" == *"HTTP 404"* ]] +} + +@test "transition-issues: handles 401 unauthorized error when getting transitions" { + set_mock_get_transitions_response '{"errorMessages":["Unauthorized"]}' "401" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error getting transitions for issue PROJ-123"* ]] + [[ "$output" == *"HTTP 401"* ]] +} + +@test "transition-issues: handles 403 forbidden error when getting transitions" { + set_mock_get_transitions_response '{"errorMessages":["Forbidden"]}' "403" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error getting transitions for issue PROJ-123"* ]] + [[ "$output" == *"HTTP 403"* ]] +} + +@test "transition-issues: handles 500 server error when getting transitions" { + set_mock_get_transitions_response '{"errorMessages":["Internal server error"]}' "500" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error getting transitions for issue PROJ-123"* ]] + [[ "$output" == *"HTTP 500"* ]] +} + +@test "transition-issues: handles 400 bad request when performing transition" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '{"errorMessages":["Transition is not valid"]}' "400" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error transitioning issue PROJ-123"* ]] + [[ "$output" == *"HTTP 400"* ]] +} + +@test "transition-issues: handles 401 unauthorized when performing transition" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '{"errorMessages":["Unauthorized"]}' "401" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error transitioning issue PROJ-123"* ]] + [[ "$output" == *"HTTP 401"* ]] +} + +@test "transition-issues: handles 500 server error when performing transition" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '{"errorMessages":["Internal server error"]}' "500" + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Error transitioning issue PROJ-123"* ]] + [[ "$output" == *"HTTP 500"* ]] +} + +@test "transition-issues: continues processing after individual failures" { + # First issue will fail to get transitions, second will succeed + # Note: This test is limited by our simple mock, but demonstrates the pattern + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123,PROJ-456" + + [ "$status" -eq 0 ] + [[ "$output" == *"JIRA transition process completed"* ]] +} + +@test "transition-issues: handles empty issue key in list" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123,,PROJ-456" + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue: PROJ-123"* ]] + [[ "$output" == *"Processing issue: PROJ-456"* ]] +} + +@test "transition-issues: processes all provided issue keys" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-1,PROJ-2,PROJ-3" + + [ "$status" -eq 0 ] + # Count how many times "Successfully transitioned" appears + success_count=$(echo "$output" | grep -c "Successfully transitioned") + [ "$success_count" -eq 3 ] +} + +@test "transition-issues: handles transition with null ID" { + set_mock_get_transitions_response '{"transitions":[{"id":null,"name":"Done"}]}' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Warning: Could not find transition"* ]] +} + +@test "transition-issues: handles different transition names" { + set_mock_get_transitions_response '{"transitions":[{"id":"11","name":"To Do"},{"id":"21","name":"In Progress"},{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "In Progress" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '21'"* ]] + [[ "$output" == *"to 'In Progress'"* ]] +} + +@test "transition-issues: prints processing summary" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123,PROJ-456" + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue keys: PROJ-123,PROJ-456"* ]] + [[ "$output" == *"JIRA transition process completed"* ]] +} + +@test "transition-issues: handles complex JIRA issue keys" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "ABC-999,DEF-1,LONG-PROJECT-NAME-12345" + + [ "$status" -eq 0 ] + [[ "$output" == *"Processing issue: ABC-999"* ]] + [[ "$output" == *"Processing issue: DEF-1"* ]] + [[ "$output" == *"Processing issue: LONG-PROJECT-NAME-12345"* ]] +} + +@test "transition-issues: matches transition name case-insensitively (lowercase input)" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"},{"id":"21","name":"In Progress"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '31'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'done'"* ]] +} + +@test "transition-issues: matches transition name case-insensitively (uppercase input)" { + set_mock_get_transitions_response '{"transitions":[{"id":"21","name":"In Progress"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "IN PROGRESS" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '21'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'IN PROGRESS'"* ]] +} + +@test "transition-issues: matches transition name case-insensitively (mixed case)" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "DoNe" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '31'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'DoNe'"* ]] +} + +@test "transition-issues: case-insensitive matching with multi-word transitions" { + set_mock_get_transitions_response '{"transitions":[{"id":"11","name":"To Do"},{"id":"21","name":"In Progress"},{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "to do" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '11'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'to do'"* ]] +} + +@test "transition-issues: case-insensitive matching when transition not found" { + set_mock_get_transitions_response '{"transitions":[{"id":"21","name":"In Progress"}]}' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Warning: Could not find transition 'done'"* ]] + [[ "$output" == *"Skipping"* ]] +} + +@test "transition-issues: exact case matching still works (backwards compatibility)" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"},{"id":"21","name":"In Progress"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "Done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '31'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'Done'"* ]] +} + +@test "transition-issues: case-insensitive with uppercase API response" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"DONE"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "done" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '31'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'done'"* ]] +} + +@test "transition-issues: case-insensitive with hyphens in transition name" { + set_mock_get_transitions_response '{"transitions":[{"id":"51","name":"Ready-for-Review"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "ready-for-review" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '51'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'ready-for-review'"* ]] +} + +@test "transition-issues: case-insensitive matching with numbers in transition name" { + set_mock_get_transitions_response '{"transitions":[{"id":"99","name":"Phase 1 Complete"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "PHASE 1 COMPLETE" "PROJ-123" + + [ "$status" -eq 0 ] + [[ "$output" == *"Found transition ID '99'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'PHASE 1 COMPLETE'"* ]] +} + +@test "transition-issues: case-insensitive across multiple issues with different case inputs" { + set_mock_get_transitions_response '{"transitions":[{"id":"31","name":"Done"}]}' + set_mock_post_transition_response '' + + run "$BATS_TEST_DIRNAME/../scripts/transition-issues.sh" "$JIRA_CONTEXT" "DONE" "PROJ-123,PROJ-456" + + [ "$status" -eq 0 ] + [[ "$output" == *"Successfully transitioned issue PROJ-123 to 'DONE'"* ]] + [[ "$output" == *"Successfully transitioned issue PROJ-456 to 'DONE'"* ]] +} diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/cache-keys.sh b/.github/actions/universal-detect-changes-and-generate-changelog/cache-keys.sh index f92be37..0df3979 100755 --- a/.github/actions/universal-detect-changes-and-generate-changelog/cache-keys.sh +++ b/.github/actions/universal-detect-changes-and-generate-changelog/cache-keys.sh @@ -1,6 +1,9 @@ #!/bin/bash set -e +# Store original prefix for debug output +ORIGINAL_CACHE_KEY_PREFIX="$CACHE_KEY_PREFIX" + # Generate cache key prefix based on input if [ -n "$CACHE_KEY_PREFIX" ]; then CACHE_KEY_PREFIX="${CACHE_KEY_PREFIX}-latest_builded_commit-" @@ -9,7 +12,8 @@ else fi # Debug output if enabled -if [ "$DEBUG" == "true" ]; then +if [ "$DEBUG" == "true" ]; then + echo "[DEBUG] CACHE_KEY_PREFIX='$ORIGINAL_CACHE_KEY_PREFIX'" echo "[DEBUG] CACHE_KEY_PREFIX='$CACHE_KEY_PREFIX'" echo "[DEBUG] CALCULATED_CACHE_KEY='$CACHE_KEY_PREFIX$GITHUB_SHA'" fi diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/generate-changelog.sh b/.github/actions/universal-detect-changes-and-generate-changelog/generate-changelog.sh index 7ade702..4e70baf 100755 --- a/.github/actions/universal-detect-changes-and-generate-changelog/generate-changelog.sh +++ b/.github/actions/universal-detect-changes-and-generate-changelog/generate-changelog.sh @@ -38,20 +38,20 @@ get_branch_names() { if [ "$from_commit" == "$to_commit" ]; then git log --merges --first-parent --pretty=format:"%s" HEAD~1..HEAD | \ sed -e "s/^Merge branch '//" -e "s/^Merge pull request .* from //" -e "s/' into.*$//" -e "s/ into.*$//" | \ - grep -v '^$' 2>&1 - return $? + grep -v '^$' 2>&1 || true + return 0 else git log --merges --first-parent --pretty=format:"%s" "${from_commit}..${to_commit}" | \ sed -e "s/^Merge branch '//" -e "s/^Merge pull request .* from //" -e "s/' into.*$//" -e "s/ into.*$//" | \ - grep -v '^$' 2>&1 - return $? + grep -v '^$' 2>&1 || true + return 0 fi } # Check if string is empty (after removing whitespace) is_empty() { local text="$1" - [ -z "$(echo "$text" | tr -d '\n\r')" ] + [ -z "$(echo "$text" | tr -d '\n\r \t')" ] } # Format changelog text @@ -141,8 +141,8 @@ main() { if [ $git_exit_code -eq 0 ]; then raw_branch_names=$(git log --merges --first-parent --pretty=format:"%s" HEAD~1..HEAD 2>&1 | \ sed -e "s/^Merge branch '//" -e "s/^Merge pull request .* from //" -e "s/' into.*$//" -e "s/ into.*$//" | \ - grep -v '^$' 2>&1) - git_exit_code=$? + grep -v '^$' 2>&1 || true) + git_exit_code=0 else raw_branch_names="" fi @@ -154,8 +154,8 @@ main() { if [ $git_exit_code -eq 0 ]; then raw_branch_names=$(git log --merges --first-parent --pretty=format:"%s" "${FROM_COMMIT}..${TO_COMMIT}" 2>&1 | \ sed -e "s/^Merge branch '//" -e "s/^Merge pull request .* from //" -e "s/' into.*$//" -e "s/ into.*$//" | \ - grep -v '^$' 2>&1) - git_exit_code=$? + grep -v '^$' 2>&1 || true) + git_exit_code=0 else raw_branch_names="" fi diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/test/run_tests.sh b/.github/actions/universal-detect-changes-and-generate-changelog/test/run_tests.sh deleted file mode 100755 index 65672de..0000000 --- a/.github/actions/universal-detect-changes-and-generate-changelog/test/run_tests.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e - -# Test runner script for the universal-detect-changes-and-generate-changelog action -# This script runs all unit tests using BATS (Bash Automated Testing System) - -echo "๐Ÿงช Running unit tests for universal-detect-changes-and-generate-changelog action..." -echo "" - -# Check if BATS is installed -if ! command -v bats &> /dev/null; then - echo "โŒ BATS is not installed. Please install it first:" - echo " macOS: brew install bats-core" - echo " Ubuntu/Debian: apt-get install bats" - echo " Or install from: https://github.com/bats-core/bats-core" - exit 1 -fi - -# Run tests with verbose output -echo "Running cache-keys tests..." -bats -v test_cache-keys.bats - -echo "" -echo "Running determine-range tests..." -bats -v test_determine-range.bats - -echo "" -echo "Running generate-changelog tests..." -bats -v test_generate-changelog.bats - -echo "" -echo "โœ… All tests completed!" diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_cache-keys.bats b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_cache-keys.bats index 80912e4..4b48f22 100755 --- a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_cache-keys.bats +++ b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_cache-keys.bats @@ -7,7 +7,7 @@ load 'test_helper' export GITHUB_SHA="abc123" export DEBUG="false" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] [ "$(grep '^cache_key_prefix=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "custom-prefix-latest_builded_commit-" ] @@ -18,7 +18,7 @@ load 'test_helper' export GITHUB_SHA="def456" export DEBUG="false" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] [ "$(grep '^cache_key_prefix=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "latest_builded_commit-" ] @@ -30,7 +30,7 @@ load 'test_helper' export GITHUB_SHA="empty123" export DEBUG="false" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] [ "$(grep '^cache_key_prefix=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "latest_builded_commit-" ] @@ -41,7 +41,7 @@ load 'test_helper' export GITHUB_SHA="whitespace123" export DEBUG="false" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] [ "$(grep '^cache_key_prefix=' "$GITHUB_OUTPUT" | cut -d= -f2)" = " -latest_builded_commit-" ] @@ -52,7 +52,7 @@ load 'test_helper' export GITHUB_SHA="special123" export DEBUG="false" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] [ "$(grep '^cache_key_prefix=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "my-app@v1.0-latest_builded_commit-" ] @@ -63,7 +63,7 @@ load 'test_helper' export GITHUB_SHA="mno345" export DEBUG="true" - run ../cache-keys.sh + run "$BATS_TEST_DIRNAME/../cache-keys.sh" [ "$status" -eq 0 ] echo "$output" | grep -q "\[DEBUG\] CACHE_KEY_PREFIX='debug-prefix'" diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_determine-range.bats b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_determine-range.bats index 451d2b7..04f22ee 100755 --- a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_determine-range.bats +++ b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_determine-range.bats @@ -23,7 +23,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "true" ] @@ -53,7 +53,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "false" ] @@ -89,7 +89,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "false" ] @@ -116,7 +116,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "true" ] @@ -141,7 +141,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "false" ] @@ -167,7 +167,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "false" ] @@ -190,7 +190,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -ne 0 ] # Should fail due to git rev-parse error cleanup_mock_files @@ -220,7 +220,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] [ "$(grep '^build_should_skip=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "false" ] @@ -250,7 +250,7 @@ load 'test_helper' } export -f git - run ../determine-range.sh + run "$BATS_TEST_DIRNAME/../determine-range.sh" [ "$status" -eq 0 ] echo "$output" | grep -q "\[DEBUG\] Previous built commit SHA from cache: 'debug-commit'" diff --git a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_generate-changelog.bats b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_generate-changelog.bats index 94be7bc..3bacca1 100755 --- a/.github/actions/universal-detect-changes-and-generate-changelog/test/test_generate-changelog.bats +++ b/.github/actions/universal-detect-changes-and-generate-changelog/test/test_generate-changelog.bats @@ -24,7 +24,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Merge commit message 1, Merge commit message 2" ] @@ -54,7 +54,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Single merge commit message" ] @@ -78,7 +78,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "No changelog provided." ] @@ -102,7 +102,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Error generating changelog: command failed." ] @@ -133,7 +133,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Message 1, Message 2" ] @@ -161,7 +161,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "No changelog provided." ] @@ -188,10 +188,10 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] - [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Message with newlines, and special chars: @#$%, and quotes: \"test\"" ] + [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Message with newlines, and special chars: @#$%25, and quotes: \"test\"" ] } @test "generate-changelog: handles empty branch names" { @@ -213,7 +213,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Some changelog message" ] @@ -242,7 +242,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^merged_branches=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "feature-1, feature-2" ] @@ -263,7 +263,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Error generating changelog: command failed." ] @@ -290,7 +290,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] local changelog=$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2) @@ -318,7 +318,7 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] echo "$output" | grep -q "\[DEBUG\] Generating changelog from debug-commit1 to debug-commit2" @@ -350,12 +350,12 @@ load 'test_helper' } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] # Quotes should be preserved and outputs remain a single line key=value (no YAML/shell breakage) [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Fix: handle \"quoted\" values in output, Ensure it's safe when there's a 'single quote' too" ] - [ "$(grep '^merged_branches=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "feature-quoted-\"name\", feature-another'quoted'branch" ] + [ "$(grep '^merged_branches=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "feature-another'quoted'branch, feature-quoted-\"name\"" ] } @test "generate-changelog: handles raw double quotes via here-doc (no escaping in source)" { @@ -384,7 +384,7 @@ EOF } export -f git - run ../generate-changelog.sh + run "$BATS_TEST_DIRNAME/../generate-changelog.sh" [ "$status" -eq 0 ] [ "$(grep '^changelog_string=' "$GITHUB_OUTPUT" | cut -d= -f2)" = "Message with \"double quotes\" inside, Another line with it's fine" ] diff --git a/.github/workflows/android-cloud-nightly-build.yml b/.github/workflows/android-cloud-nightly-build.yml index edcb878..21ab847 100644 --- a/.github/workflows/android-cloud-nightly-build.yml +++ b/.github/workflows/android-cloud-nightly-build.yml @@ -81,6 +81,11 @@ on: required: false type: number default: 30 + JIRA_TRANSITION: + description: "Jira transition to use for transitioning related issues after build" + required: false + type: string + default: 'Testing' secrets: APP_DISTRIBUTION_SERVICE_ACCOUNT: @@ -92,6 +97,9 @@ on: SECRET_PROPERTIES: required: false description: "Custom string that contains key-value properties as secrets. Contents of this secret will be placed into file specified by 'SECRET_PROPERTIES_FILE' input." + JIRA_CONTEXT: + required: false + description: "JIRA context for transitioning tickets." jobs: changelog: @@ -99,6 +107,7 @@ jobs: skip_build: ${{ steps.detect_changes.outputs.skip_build }} changelog: ${{ steps.detect_changes.outputs.changelog }} cache_key: ${{ steps.detect_changes.outputs.cache_key }} + merged_branches: ${{ steps.detect_changes.outputs.merged_branches }} name: Detect changes and generate changelog runs-on: ubuntu-latest steps: @@ -156,3 +165,29 @@ jobs: with: path: latest_builded_commit.txt key: ${{ needs.changelog.outputs.cache_key }} + transition_jira_tickets: + name: Transition JIRA tickets + runs-on: ubuntu-latest + needs: [ changelog, build ] + if: success() && needs.changelog.outputs.skip_build != 'true' + steps: + - name: Check JIRA context + id: check + env: + JIRA_CONTEXT: ${{ secrets.JIRA_CONTEXT }} + run: | + if [ -z "$JIRA_CONTEXT" ]; then + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "โ„น๏ธ JIRA ticket transition skipped - no JIRA context provided." + echo "๐Ÿ’ก Tip: You can automatically transition JIRA tickets by passing the 'JIRA_CONTEXT' secret." + else + echo "enabled=true" >> "$GITHUB_OUTPUT" + fi + - name: Transition JIRA tickets + if: steps.check.outputs.enabled == 'true' + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: ${{ inputs.JIRA_TRANSITION }} + merged_branches: ${{ needs.changelog.outputs.merged_branches }} + diff --git a/.github/workflows/ios-selfhosted-nightly-build.yml b/.github/workflows/ios-selfhosted-nightly-build.yml index 1b35256..8eef5fc 100644 --- a/.github/workflows/ios-selfhosted-nightly-build.yml +++ b/.github/workflows/ios-selfhosted-nightly-build.yml @@ -42,6 +42,12 @@ on: description: 'Custom string that can contains values specified in your workflow file. Those values will be placed into environment variable. Example: "CUSTOM-1: 1; CUSTOM-2: 2"' type: string required: false + default: '24 hours' + jira_transition: + description: 'The name of the JIRA transition to apply to tickets found in merged branches.' + type: string + required: false + default: 'Testing' secrets: MATCH_PASSWORD: @@ -59,11 +65,17 @@ on: SECRET_PROPERTIES: required: false description: 'Secrets in the format KEY = VALUE (one per line).' + JIRA_CONTEXT: + required: false + description: 'JIRA context for transitioning tickets.' jobs: build: runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner_label)) }} timeout-minutes: ${{ inputs.timeout_minutes }} + outputs: + skip_build: ${{ steps.detect_changes.outputs.skip_build }} + merged_branches: ${{ steps.detect_changes.outputs.merged_branches }} steps: - name: Detect changes and generate changelog @@ -92,11 +104,11 @@ jobs: if: ${{ steps.detect_changes.outputs.skip_build == 'false' }} uses: futuredapp/.github/.github/actions/ios-fastlane-beta@main with: - MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + match_password: ${{ secrets.MATCH_PASSWORD }} testflight_changelog: ${{ steps.set_changelog.outputs.changelog }} - APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }} - APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }} - APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }} + app_store_connect_api_key_key: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }} + app_store_connect_api_key_key_id: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }} + app_store_connect_api_key_issuer_id: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }} custom_values: ${{ inputs.custom_values }} - name: Upload IPA @@ -125,3 +137,29 @@ jobs: with: path: latest_builded_commit.txt key: ${{ steps.detect_changes.outputs.cache_key }} + + transition_jira_tickets: + name: Transition JIRA tickets + runs-on: ubuntu-latest + needs: build + if: success() && needs.build.outputs.skip_build != 'true' + steps: + - name: Check JIRA context + id: check + env: + JIRA_CONTEXT: ${{ secrets.JIRA_CONTEXT }} + run: | + if [ -z "$JIRA_CONTEXT" ]; then + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "โ„น๏ธ JIRA ticket transition skipped - no JIRA context provided." + echo "๐Ÿ’ก Tip: You can automatically transition JIRA tickets by passing the 'JIRA_CONTEXT' secret." + else + echo "enabled=true" >> "$GITHUB_OUTPUT" + fi + - name: Transition JIRA tickets + if: steps.check.outputs.enabled == 'true' + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: ${{ inputs.jira_transition }} + merged_branches: ${{ needs.build.outputs.merged_branches }} diff --git a/.github/workflows/kmp-combined-nightly-build.yml b/.github/workflows/kmp-combined-nightly-build.yml index 870a7e3..38c385d 100644 --- a/.github/workflows/kmp-combined-nightly-build.yml +++ b/.github/workflows/kmp-combined-nightly-build.yml @@ -105,6 +105,11 @@ on: type: string required: false default: "24 hours" + JIRA_TRANSITION: + description: "The name of the JIRA transition to apply to tickets found in merged branches." + type: string + required: false + default: "Testing" secrets: FIREBASE_APP_DISTRIBUTION_SERVICE_ACCOUNT: @@ -131,6 +136,9 @@ on: IOS_APP_STORE_CONNECT_API_KEY_ISSUER_ID: required: true description: "Private App Store Connect API issuer key for submitting build to App Store." + JIRA_CONTEXT: + required: false + description: "JIRA context for transitioning tickets." jobs: changelog: @@ -138,6 +146,7 @@ jobs: skip_build: ${{ steps.detect_changes.outputs.skip_build }} changelog: ${{ steps.detect_changes.outputs.changelog }} cache_key: ${{ steps.detect_changes.outputs.cache_key }} + merged_branches: ${{ steps.detect_changes.outputs.merged_branches }} name: Detect changes and generate changelog runs-on: ubuntu-latest steps: @@ -183,7 +192,7 @@ jobs: kmp_swift_package_flavor: ${{ inputs.KMP_FLAVOR }} custom_values: ${{ inputs.IOS_CUSTOM_VALUES }} testflight_changelog: ${{ needs.changelog.outputs.changelog }} - ios_custom_build_path: ${{ inputs.ios_custom_build_path }} + ios_custom_build_path: ${{ inputs.IOS_CUSTOM_BUILD_PATH }} android_build: name: Android Build @@ -241,3 +250,28 @@ jobs: path: latest_builded_commit.txt key: ${{ needs.changelog.outputs.cache_key }} + transition_jira_tickets: + name: Transition JIRA tickets + runs-on: ubuntu-latest + needs: [ changelog, ios_build, android_build ] + if: success() && needs.changelog.outputs.skip_build != 'true' + steps: + - name: Check JIRA context + id: check + env: + JIRA_CONTEXT: ${{ secrets.JIRA_CONTEXT }} + run: | + if [ -z "$JIRA_CONTEXT" ]; then + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "โ„น๏ธ JIRA ticket transition skipped - no JIRA context provided." + echo "๐Ÿ’ก Tip: You can automatically transition JIRA tickets by passing the 'JIRA_CONTEXT' secret." + else + echo "enabled=true" >> "$GITHUB_OUTPUT" + fi + - name: Transition JIRA tickets + if: steps.check.outputs.enabled == 'true' + uses: futuredapp/.github/.github/actions/jira-transition-tickets@main + with: + jira_context: ${{ secrets.JIRA_CONTEXT }} + transition: ${{ inputs.JIRA_TRANSITION }} + merged_branches: ${{ needs.changelog.outputs.merged_branches }} diff --git a/.github/workflows/test-universal-detect-changes.yml b/.github/workflows/test-universal-detect-changes.yml deleted file mode 100644 index 6db99d1..0000000 --- a/.github/workflows/test-universal-detect-changes.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Test Universal Detect Changes Action - -on: - pull_request: - paths: - - '.github/actions/universal-detect-changes-and-generate-changelog/**' - - '.github/workflows/test-universal-detect-changes.yml' - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 10 - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install BATS - run: | - sudo apt-get update - sudo apt-get install -y bats - - - name: Run all tests - run: | - cd .github/actions/universal-detect-changes-and-generate-changelog - ./test/run_tests.sh - - - name: Test action.yml syntax - run: | - # Validate action.yml syntax - python3 -c " - import yaml - with open('.github/actions/universal-detect-changes-and-generate-changelog/action.yml', 'r') as f: - yaml.safe_load(f) - print('action.yml syntax is valid') - " diff --git a/.github/workflows/workflows-lint.yml b/.github/workflows/workflows-lint.yml index 27a85b3..a036612 100644 --- a/.github/workflows/workflows-lint.yml +++ b/.github/workflows/workflows-lint.yml @@ -1,9 +1,10 @@ -name: Lint GitHub Actions workflows +name: Check Pull Request on: [pull_request] jobs: actionlint: + name: Lint GitHub Actions workflows runs-on: ubuntu-latest timeout-minutes: 30 @@ -19,3 +20,18 @@ jobs: - name: Check workflow files run: ${{ steps.get_actionlint.outputs.executable }} -color shell: bash + + tests: + name: Test Actions + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Bats + id: install_bats + uses: bats-core/bats-action@3.0.1 + - name: Run tests + shell: bash + run: bats -r .