Skip to content

Commit 0b4535d

Browse files
authored
Merge pull request #27 from redis/release_automation
Release automation for SNAP
2 parents 2b48d96 + a422421 commit 0b4535d

File tree

17 files changed

+1277
-256
lines changed

17 files changed

+1277
-256
lines changed

.github/actions/build/action.yml

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: 'Build Redis Snap'
2+
description: 'Build Redis snap package with configurable version'
3+
inputs:
4+
version:
5+
description: 'Redis version to build (e.g., "unstable", "8.4-rc1", or a tag like "7.2.4")'
6+
required: true
7+
architecture:
8+
description: 'Architecture to build for (amd64 or arm64)'
9+
required: true
10+
outputs:
11+
packages_list:
12+
description: 'JSON list of built snap files'
13+
value: ${{ steps.list-packages.outputs.packages_list }}
14+
15+
runs:
16+
using: 'composite'
17+
steps:
18+
- name: Checkout Redis repository
19+
uses: actions/checkout@v4
20+
with:
21+
repository: redis/redis
22+
path: redis
23+
ref: ${{ inputs.version }}
24+
25+
- name: Configure Redis modules to use master
26+
if: inputs.version == 'unstable'
27+
shell: bash
28+
run: |
29+
echo "Updating module versions to use master branch"
30+
for module in redisbloom redisearch redistimeseries redisjson; do
31+
if [ -f "redis/modules/${module}/Makefile" ]; then
32+
echo "Updating ${module} to use master branch"
33+
sed -i 's/MODULE_VERSION = .*/MODULE_VERSION = master/' "redis/modules/${module}/Makefile"
34+
echo "Verifying ${module} version: $(grep "MODULE_VERSION" "redis/modules/${module}/Makefile")"
35+
fi
36+
done
37+
38+
- name: Setup Snapcraft
39+
shell: bash
40+
run: |
41+
sudo snap install snapcraft --classic
42+
43+
- name: Setup LXD
44+
uses: canonical/[email protected]
45+
46+
- name: Build Snap
47+
shell: bash
48+
env:
49+
SNAPCRAFT_BUILD_INFO: 1
50+
run: |
51+
sudo snapcraft
52+
53+
- name: List built packages
54+
id: list-packages
55+
shell: bash
56+
run: |
57+
packages=$(ls *.snap | jq -R -s -c 'split("\n") | map(select(length > 0))')
58+
echo "packages_list=$packages" >> $GITHUB_OUTPUT
59+
echo "Built packages: $packages"
60+
61+
- name: Upload to artifacts
62+
uses: actions/upload-artifact@v4
63+
with:
64+
name: redis-snap-${{ inputs.architecture }}-${{ github.sha }}
65+
path: '*.snap'
66+
retention-days: 1
67+
68+
- name: Capture build logs on failure
69+
if: failure() && inputs.version == 'unstable'
70+
shell: bash
71+
run: |
72+
mkdir -p /tmp/build-logs
73+
74+
echo "Build failed for snap on ${{ inputs.architecture }}"
75+
echo "Capturing detailed logs for troubleshooting..."
76+
77+
# Get system info
78+
uname -a > /tmp/build-logs/system-info.log 2>&1
79+
snap --version > /tmp/build-logs/snap-info.log 2>&1
80+
snapcraft --version >> /tmp/build-logs/snap-info.log 2>&1
81+
82+
# Get LXD container info
83+
lxc list > /tmp/build-logs/lxc-list.log 2>&1 || echo "Failed to list LXC containers"
84+
lxc info > /tmp/build-logs/lxc-info.log 2>&1 || echo "Failed to get LXC info"
85+
86+
# Get snap environment info
87+
snap list > /tmp/build-logs/snap-list.log 2>&1
88+
89+
# Get Redis source info
90+
if [ -d "redis" ]; then
91+
(cd redis && git log -n 3) > /tmp/build-logs/redis-git-info.log 2>&1
92+
find redis/modules -name "Makefile" -exec grep "MODULE_VERSION" {} \; > /tmp/build-logs/module-versions.log 2>&1
93+
fi
94+
95+
# Get snap parts info if they exist
96+
if [ -d "parts" ]; then
97+
find parts -name "*.log" -exec cp {} /tmp/build-logs/ \; || echo "No part logs found"
98+
find parts -type f -name "*.log" | sort > /tmp/build-logs/parts-logs-list.txt 2>&1
99+
fi
100+
101+
# Create a summary file
102+
{
103+
echo "Build failure summary for snap on ${{ inputs.architecture }}"
104+
echo "Date: $(date)"
105+
echo "GitHub SHA: ${{ github.sha }}"
106+
echo "Architecture: ${{ inputs.architecture }}"
107+
echo "Version: ${{ inputs.version }}"
108+
} > /tmp/build-logs/failure-summary.txt
109+
110+
echo "Log capture complete"
111+
112+
- name: Upload build failure logs
113+
if: failure() && inputs.version == 'unstable'
114+
uses: actions/upload-artifact@v4
115+
with:
116+
name: build-failure-${{ inputs.architecture }}-snap
117+
path: /tmp/build-logs/
118+
retention-days: 30
119+
if-no-files-found: warn
120+

.github/actions/common/slack.sh

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/bin/bash
2+
3+
4+
# Send a Slack message using Bot Token API
5+
# Reads JSON message from stdin, sends to Slack API
6+
# Usage: slack_send_with_token "$SLACK_BOT_TOKEN" < message.json
7+
slack_send_with_token() {
8+
set -x
9+
local token="$1"
10+
local curl_stderr=$(mktemp)
11+
12+
# Run curl with verbose output, stderr to curl_stderr
13+
if ! curl --fail-with-body -v -X POST https://api.slack.com/api/chat.postMessage \
14+
-H "Authorization: Bearer $token" \
15+
-H "Content-Type: application/json" \
16+
-d @- 2>"$curl_stderr"; then
17+
# If curl failed, output the error log
18+
echo "curl command failed. Error log:" >&2
19+
cat "$curl_stderr" >&2
20+
rm -f "$curl_stderr"
21+
return 1
22+
fi
23+
24+
rm -f "$curl_stderr"
25+
return 0
26+
}
27+
28+
# Handle Slack API response and extract message metadata
29+
# Reads JSON response from stdin
30+
# If GITHUB_OUTPUT is set, writes slack_ts and slack_url to it
31+
# Usage: slack_handle_message_result "$SLACK_CHANNEL_ID" < response.json
32+
slack_handle_message_result() {
33+
set -x
34+
local channel_id="$1"
35+
local message="$2"
36+
local response=$(cat)
37+
38+
echo "Slack API Response:"
39+
40+
# Check if successful
41+
if echo "$response" | jq -e '.ok == true' > /dev/null; then
42+
local slack_ts=$(echo "$response" | jq -r '.ts')
43+
local slack_channel=$(echo "$response" | jq -r '.channel')
44+
45+
# Convert timestamp to URL format (remove dot)
46+
local ts_for_url=$(echo "$slack_ts" | tr -d '.')
47+
local slack_url="https://redis.slack.com/archives/${slack_channel}/p${ts_for_url}"
48+
49+
# Write to GITHUB_OUTPUT if available
50+
if [ -n "$GITHUB_OUTPUT" ]; then
51+
echo "slack_ts=$slack_ts" >> "$GITHUB_OUTPUT"
52+
echo "slack_url=$slack_url" >> "$GITHUB_OUTPUT"
53+
fi
54+
55+
echo "✅ Message sent successfully!"
56+
echo "Message URL: $slack_url"
57+
return 0
58+
else
59+
local error=$(echo "$response" | jq -r '.error // "unknown"')
60+
echo "❌ Failed to send Slack message: $error" >&2
61+
echo "$response" | jq '.'
62+
echo "Message content: $message" >&2
63+
return 1
64+
fi
65+
}
66+
67+
slack_format_success_message() {
68+
jq --arg channel "$1" --arg release_tag "$2" --arg footer "$3" --arg env "$4" '
69+
{
70+
"channel": $channel,
71+
"icon_emoji": ":redis-circle:",
72+
"text": (":ubuntu: SNAP Packages Published for Redis: " + $release_tag + " (" + $env + ")"),
73+
"blocks": (
74+
[
75+
{
76+
"type": "header",
77+
"text": { "type": "plain_text", "text": (":ubuntu: SNAP Packages Published for Release " + $release_tag + " (" + $env + ")") }
78+
},
79+
{
80+
"type": "section",
81+
"text": {
82+
"type": "mrkdwn",
83+
"text": "The following packages have been published to https://snapcraft.io/redis"
84+
}
85+
}
86+
] +
87+
map({
88+
"type": "section",
89+
"text": {
90+
"type": "mrkdwn",
91+
"text": ("*" + .file + "* (revision: " + .revision + ")")
92+
}
93+
}) +
94+
[
95+
{
96+
"type": "context",
97+
"elements": [
98+
{ "type": "mrkdwn", "text": $footer }
99+
]
100+
}
101+
]
102+
)
103+
}'
104+
}
105+
106+
slack_format_failure_message() {
107+
channel=$1
108+
header=$2
109+
workflow_url=$3
110+
footer=$4
111+
if [ -z "$header" ]; then
112+
header=" "
113+
fi
114+
if [ -z "$footer" ]; then
115+
footer=" "
116+
fi
117+
118+
# Create Slack message payload
119+
cat << EOF
120+
{
121+
"channel": "$channel",
122+
"icon_emoji": ":redis-circle:",
123+
"text": "$header",
124+
"blocks": [
125+
{
126+
"type": "header",
127+
"text": {
128+
"type": "plain_text",
129+
"text": "❌ $header"
130+
}
131+
},
132+
{
133+
"type": "section",
134+
"text": {
135+
"type": "mrkdwn",
136+
"text": "Workflow run: $workflow_url"
137+
}
138+
},
139+
{
140+
"type": "context",
141+
"elements": [
142+
{
143+
"type": "mrkdwn",
144+
"text": "$footer"
145+
}
146+
]
147+
}
148+
]
149+
}
150+
EOF
151+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: 'Determine Redis Version'
2+
description: 'Determine Redis version to build based on risk level from .redis_versions.json'
3+
inputs:
4+
risk_level:
5+
description: 'Risk level (edge, candidate, stable)'
6+
required: true
7+
8+
outputs:
9+
redis_version:
10+
description: 'Redis version to build (e.g., "8.4.0", "unstable")'
11+
value: ${{ steps.determine-version.outputs.redis_version }}
12+
13+
runs:
14+
using: 'composite'
15+
steps:
16+
- name: Validate risk level
17+
shell: bash
18+
run: |
19+
if [[ ! "${{ inputs.risk_level }}" =~ ^(edge|candidate|stable)$ ]]; then
20+
echo "Error: risk_level must be one of: edge, candidate, stable"
21+
echo "Provided value: ${{ inputs.risk_level }}"
22+
exit 1
23+
fi
24+
echo "Risk level validation passed: ${{ inputs.risk_level }}"
25+
26+
- name: Determine Redis version from risk level
27+
id: determine-version
28+
shell: bash
29+
run: |
30+
if [ ! -f ".redis_versions.json" ]; then
31+
echo "Error: .redis_versions.json not found"
32+
exit 1
33+
fi
34+
35+
REDIS_VERSION=$(jq -r ".${{ inputs.risk_level }}" .redis_versions.json)
36+
37+
if [ "$REDIS_VERSION" = "null" ] || [ -z "$REDIS_VERSION" ]; then
38+
echo "Error: Risk level '${{ inputs.risk_level }}' not found in .redis_versions.json"
39+
echo "Available risk levels:"
40+
jq -r 'keys[]' .redis_versions.json
41+
exit 1
42+
fi
43+
44+
echo "Risk level: ${{ inputs.risk_level }}"
45+
echo "Redis version: $REDIS_VERSION"
46+
echo "redis_version=$REDIS_VERSION" >> $GITHUB_OUTPUT
47+

0 commit comments

Comments
 (0)