1+ name : Create Release
2+
3+ on :
4+ push :
5+ tags :
6+ # Matches release/<namespace>/<resource_name>/<semantic_version>
7+ # (e.g., "release/coder-labs/sourcegraph-amp/v1.0.1")
8+ - " release/*/*/v*.*.*"
9+
10+ jobs :
11+ create-release :
12+ runs-on : ubuntu-latest
13+ permissions :
14+ contents : write
15+ pull-requests : read
16+
17+ steps :
18+ - name : Checkout code
19+ uses : actions/checkout@v4
20+ with :
21+ fetch-depth : 0 # Fetch full history for changelog generation
22+
23+ - name : Extract tag information
24+ id : tag_info
25+ run : |
26+ TAG=${GITHUB_REF#refs/tags/}
27+ echo "tag=$TAG" >> $GITHUB_OUTPUT
28+
29+ # Extract namespace, module, and version from tag
30+ # Format: release/namespace/module/version
31+ IFS='/' read -ra PARTS <<< "$TAG"
32+ NAMESPACE="${PARTS[1]}"
33+ MODULE="${PARTS[2]}"
34+ VERSION="${PARTS[3]}"
35+
36+ echo "namespace=$NAMESPACE" >> $GITHUB_OUTPUT
37+ echo "module=$MODULE" >> $GITHUB_OUTPUT
38+ echo "version=$VERSION" >> $GITHUB_OUTPUT
39+ echo "module_path=registry/$NAMESPACE/modules/$MODULE" >> $GITHUB_OUTPUT
40+
41+ # Create release title
42+ RELEASE_TITLE="$NAMESPACE/$MODULE $VERSION"
43+ echo "release_title=$RELEASE_TITLE" >> $GITHUB_OUTPUT
44+
45+ - name : Find previous tag
46+ id : prev_tag
47+ run : |
48+ NAMESPACE="${{ steps.tag_info.outputs.namespace }}"
49+ MODULE="${{ steps.tag_info.outputs.module }}"
50+ CURRENT_TAG="${{ steps.tag_info.outputs.tag }}"
51+
52+ # Find the previous tag for this specific module
53+ PREV_TAG=$(git tag -l "release/$NAMESPACE/$MODULE/v*" | grep -v "$CURRENT_TAG" | sort -V | tail -1)
54+
55+ if [ -z "$PREV_TAG" ]; then
56+ echo "No previous tag found, using initial commit"
57+ PREV_TAG=$(git rev-list --max-parents=0 HEAD)
58+ fi
59+
60+ echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT
61+ echo "Previous tag: $PREV_TAG"
62+
63+ - name : Generate changelog
64+ id : changelog
65+ run : |
66+ NAMESPACE="${{ steps.tag_info.outputs.namespace }}"
67+ MODULE="${{ steps.tag_info.outputs.module }}"
68+ MODULE_PATH="${{ steps.tag_info.outputs.module_path }}"
69+ PREV_TAG="${{ steps.prev_tag.outputs.prev_tag }}"
70+ CURRENT_TAG="${{ steps.tag_info.outputs.tag }}"
71+
72+ echo "Generating changelog for $MODULE_PATH between $PREV_TAG and $CURRENT_TAG"
73+
74+ # Get commits that affected the specific module path
75+ COMMITS=$(git log --oneline --no-merges "$PREV_TAG..$CURRENT_TAG" -- "$MODULE_PATH" | cut -d' ' -f1)
76+
77+ if [ -z "$COMMITS" ]; then
78+ echo "No commits found for this module"
79+ echo "changelog=No changes found for this module." >> $GITHUB_OUTPUT
80+ exit 0
81+ fi
82+
83+ # Generate changelog from commits
84+ CHANGELOG="## What's Changed\n\n"
85+
86+ for commit in $COMMITS; do
87+ # Get commit message
88+ COMMIT_MSG=$(git log --format="%s" -n 1 $commit)
89+
90+ # Extract PR number from commit message (handles various formats)
91+ PR_NUM=$(echo "$COMMIT_MSG" | grep -oE '\(#[0-9]+\)|#[0-9]+' | grep -oE '[0-9]+' | head -1 || echo "")
92+
93+ # Get GitHub username from commit (try multiple methods)
94+ # First try to get from commit trailer
95+ GH_USER=$(git log --format="%(trailers:key=Co-authored-by,valueonly)" -n 1 $commit | head -1 | grep -oE '@[^>]+' | cut -d'@' -f2 | cut -d'.' -f1 || echo "")
96+
97+ # If no co-author, try to extract from email
98+ if [ -z "$GH_USER" ]; then
99+ EMAIL=$(git log --format="%ae" -n 1 $commit)
100+ if [[ "$EMAIL" == *"@users.noreply.github.com" ]]; then
101+ GH_USER=$(echo "$EMAIL" | cut -d'@' -f1 | sed 's/^[0-9]*+//')
102+ else
103+ GH_USER=$(echo "$EMAIL" | cut -d'@' -f1)
104+ fi
105+ fi
106+
107+ # Fallback to commit author name if no GitHub username found
108+ if [ -z "$GH_USER" ]; then
109+ GH_USER=$(git log --format="%an" -n 1 $commit | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
110+ fi
111+
112+ # Format changelog entry
113+ if [ -n "$PR_NUM" ]; then
114+ CHANGELOG="${CHANGELOG}* $COMMIT_MSG by @$GH_USER in https://github.com/coder/registry/pull/$PR_NUM\n"
115+ else
116+ CHANGELOG="${CHANGELOG}* $COMMIT_MSG by @$GH_USER\n"
117+ fi
118+ done
119+
120+ # Add full changelog link
121+ CHANGELOG="${CHANGELOG}\n\n**Full Changelog**: https://github.com/coder/registry/compare/$PREV_TAG...$CURRENT_TAG"
122+
123+ # Save changelog to output (escape newlines for GitHub Actions)
124+ echo "changelog<<EOF" >> $GITHUB_OUTPUT
125+ echo -e "$CHANGELOG" >> $GITHUB_OUTPUT
126+ echo "EOF" >> $GITHUB_OUTPUT
127+
128+ - name : Create Release
129+ env :
130+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
131+ run : |
132+ gh release create "${{ steps.tag_info.outputs.tag }}" \
133+ --title "${{ steps.tag_info.outputs.release_title }}" \
134+ --notes "${{ steps.changelog.outputs.changelog }}" \
135+ --latest
0 commit comments