🤖 Auto-generated by weekly-pattern-learner · changelog-generator, store-listing-copy, and apple-store-submit each reference each other in their Chaining tables but no skill chains them into a single end-to-end release-day workflow
Release Day
Drive a release from "code is ready" to "build submitted" in one orchestrated pass. Each phase validates its output before proceeding: the skill stops and reports rather than pushing a broken release.
Inputs
- Platform (required):
ios,android,garmin, orall - Version (optional): explicit version to release; if omitted, semantic-release determines the next version automatically
- Branch (optional, default:
main): branch to release from - --dry-run (optional): run all checks and generate all copy without pushing the tag or submitting to the store
Phase 1: Verify the branch is ready
BRANCH="${Branch:-main}"
git fetch origin "$BRANCH"
BRANCH_SHA=$(git rev-parse "origin/$BRANCH")
# Validate optional Version input
if [ -n "$Version" ]; then
if ! echo "$Version" | grep -qE '^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
echo "Error: Version '$Version' is not a valid SemVer (e.g. 1.2.3 or v1.2.3)" >&2
exit 1
fi
fi
git status --short
# Last release tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
# Commits since last release
if [ "$LAST_TAG" = "none" ]; then
git log "origin/$BRANCH" --oneline --no-merges | head -20
else
git log "${LAST_TAG}..origin/$BRANCH" --oneline --no-merges | head -20
fi
# CI state on branch
gh run list --branch "$BRANCH" --limit 3 --json status,conclusion,workflowName \
--jq '.[] | "\(.workflowName): \(.conclusion // .status)"'
Stop if:
git status --shortis non-empty: there are uncommitted changes- The latest CI run on main is failing or still in progress
- There are zero commits since the last tag (nothing to release)
Report the problem clearly and stop. Do not proceed to a release if the branch is not clean and green.
Phase 2: Generate changelog
Run olko:changelog-generator.
Use the range ${LAST_TAG}..origin/${BRANCH} (or origin/${BRANCH} if no prior tag exists). Produce a
structured changelog with sections: New Features, Improvements, Bug Fixes, Breaking
Changes. Strip internal commits (refactor, test, ci, chore without behavior impact).
Write the changelog to:
RELEASE_DIR="$(mktemp -d)/release-$(date +%Y-%m-%d)"
mkdir -p "$RELEASE_DIR"
# changelog-generator writes to CHANGELOG.md: validate before proceeding
if [ ! -s CHANGELOG.md ]; then
echo "Error: CHANGELOG.md is missing or empty, cannot continue." >&2
exit 1
fi
cp CHANGELOG.md "$RELEASE_DIR/changelog.md"
Review the generated changelog for accuracy before continuing. If commits are
ambiguous (e.g. fix: thing), use git show <sha> to read the diff and
re-classify the entry.
Phase 3: Draft store listing copy
Run olko:store-listing-copy with --platform <platform>.
This reads the changelog from Phase 2 and drafts:
- iOS: Title, Subtitle, What's New (4000 chars), Keywords (100 chars)
- Android: Title (30), Short Description (80), Release Notes (500)
- Garmin: Description, What's New (1500 chars)
The skill validates field lengths and known store-validator rules (e.g., no </> in
Garmin copy) before delivering. Output goes to:
store-copy-v<version>-<YYYY-MM-DD>.md
Do not proceed until store copy passes validation. Fix any overflow or forbidden character before tagging.
Phase 4: Trigger the release
If semantic-release is configured
# Dry-run first to confirm version and release notes
set -o pipefail
if ! npm run release:dry-run 2>&1 | tail -40; then
echo "Dry-run failed, aborting release." >&2
exit 1
fi
# On confirmation (or with --dry-run: stop here)
git push origin "$BRANCH" # trigger CI which runs semantic-release
Wait for the GitHub Actions release workflow to complete:
# Capture run ID for the push commit so we poll the right run
sleep 10
RUN_ID=$(gh run list --branch "$BRANCH" --workflow ci-release.yml --limit 1 \
--json databaseId,headSha \
--jq "[.[] | select(.headSha == \"$BRANCH_SHA\")] | .[0].databaseId")
# Poll until the targeted run is done (timeout: 15 min)
STATUS="pending"
for i in $(seq 1 30); do
STATUS=$(gh run view "$RUN_ID" --json conclusion \
--jq '.conclusion // "pending"' 2>/dev/null || echo "pending")
[ "$STATUS" = "success" ] && break
[ "$STATUS" = "failure" ] || [ "$STATUS" = "cancelled" ] || [ "$STATUS" = "timed_out" ] && \
echo "Release workflow ended with status: $STATUS" && exit 1
sleep 30
done
if [ "$STATUS" != "success" ]; then
echo "Release workflow timed out after 15 minutes." >&2
exit 1
fi
If releasing manually (no semantic-release)
# Determine next version (follow SemVer: breaking → major, new feature → minor, fix → patch)
NEXT_VERSION="vX.Y.Z" # fill in based on changelog analysis
# Tag and push
git tag -a "$NEXT_VERSION" -m "Release $NEXT_VERSION"
git push origin "$NEXT_VERSION"
# Create GitHub release
gh release create "$NEXT_VERSION" \
--title "$NEXT_VERSION" \
--notes-file "$RELEASE_DIR/changelog.md"
Phase 5: Confirm build artifact
Download and validate the platform-specific build artifact. Poll every 2 minutes (timeout: 20 min). Do not proceed to Phase 6 until the artifact is confirmed present.
ARTIFACT_FOUND=false
for i in $(seq 1 10); do
gh run download "$RUN_ID" --dir "$RELEASE_DIR" 2>/dev/null || true
case "$Platform" in
ios)
IPA=$(find "$RELEASE_DIR" -name "*.ipa" | head -1)
[ -n "$IPA" ] && ARTIFACT_FOUND=true && echo "iOS artifact: $IPA" && break
;;
android)
APK=$(find "$RELEASE_DIR" \( -name "*.apk" -o -name "*.aab" \) | head -1)
[ -n "$APK" ] && ARTIFACT_FOUND=true && echo "Android artifact: $APK" && break
;;
garmin)
PRG=$(find "$RELEASE_DIR" dist -name "*.prg" 2>/dev/null | head -1)
[ -n "$PRG" ] && ARTIFACT_FOUND=true && echo "Garmin artifact: $PRG" && break
;;
all)
IPA=$(find "$RELEASE_DIR" -name "*.ipa" | head -1)
APK=$(find "$RELEASE_DIR" \( -name "*.apk" -o -name "*.aab" \) | head -1)
PRG=$(find "$RELEASE_DIR" dist -name "*.prg" 2>/dev/null | head -1)
[ -n "$IPA" ] && [ -n "$APK" ] && [ -n "$PRG" ] && ARTIFACT_FOUND=true && break
;;
esac
echo "Attempt $i/10: artifact not yet available, waiting 2 minutes..."
sleep 120
done
if [ "$ARTIFACT_FOUND" != "true" ]; then
echo "Error: required build artifact not found after 20 minutes, aborting." >&2
exit 1
fi
Phase 6: Submit to the store
Skip this phase with --dry-run: stop after Phase 3 and print the store copy
for manual paste.
Run the platform-specific submission workflow with the artifact from Phase 5:
iOS: Run olko:apple-store-submit: handles altool / xcrun notarytool
submission, watches for Apple's processing email, and catches common rejection patterns.
Android: Upload the .aab (or .apk) to Google Play using fastlane supply:
fastlane supply \
--aab "$APK" \
--track internal \
--package_name "$(cat android/app/build.gradle | grep applicationId | awk '{print $2}' | tr -d '"')"
Promote from internal → production after QA sign-off.
Garmin: Run olko:garmin-watchface store publishing workflow: uploads the .prg
and the listing copy from Phase 3 via the Connect IQ developer portal.
all: Run iOS → Android → Garmin in sequence; report each result independently.
Final report
Release day complete: YYYY-MM-DD
Version: vX.Y.Z (was vA.B.C)
Platform: ios / android / garmin / all
Changelog: N features, M fixes, K improvements
Store copy: validated ✓ (all fields within limits)
Release: tagged + GitHub Release created ✓
Build: CI green, artifact downloaded ✓
Submission: queued for App Store / Google Play / Connect IQ review
Next:
- Check Apple / Google / Garmin review status in 24–72h
- Monitor crash rates via Crashlytics / Firebase after rollout
- Run /review-past-performance at end of day to capture release learnings
Safety guardrails
- Never push a tag or trigger a release if Phase 1 fails
- Never submit a store build without a validated Phase 3 output
- Always
--dry-runfirst on a new repo or a new platform - Keep the store copy file in $RELEASE_DIR until the submission is confirmed live
Chaining
| Before this skill | After this skill |
|---|---|
olko:pr-to-green: merge the release PR |
Monitor store review status |
olko:semantic-release-beta: promote beta to stable |
olko:changelog-generator for next iteration |
| Manual: "all features are in, ship it" | Post-release monitoring |