Skip to content

Commit 26c683c

Browse files
authored
Implemented release workflow with tag/version validation (#35) (#39)
1 parent 0a35024 commit 26c683c

File tree

5 files changed

+399
-0
lines changed

5 files changed

+399
-0
lines changed

.github/workflows/release.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
name: release
3+
4+
5+
on:
6+
push:
7+
tags: [ "v[0-9]+*" ]
8+
branches:
9+
- main
10+
11+
env:
12+
BUILD_PACKAGES: build/packages
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
19+
verify-tag:
20+
if: startsWith(github.ref, 'refs/tags/')
21+
runs-on: ubuntu-latest
22+
outputs:
23+
tag_name: ${{ steps.get_tag.outputs.tag_name }}
24+
steps:
25+
- uses: actions/checkout@v6
26+
- id: get_tag
27+
run: |
28+
source ./tools/read_properties.sh
29+
read_properties project.properties PROJECT_PROPERTIES
30+
31+
TAG_NAME="${GITHUB_REF#refs/tags/}"
32+
EXPECTED_TAG="v${PROJECT_PROPERTIES_VERSION}"
33+
34+
if [[ "${TAG_NAME}" != "${EXPECTED_TAG}" ]]; then
35+
echo "Tag (${TAG_NAME}) does not match project.properties version (${EXPECTED_TAG})."
36+
exit 1
37+
fi
38+
39+
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
40+
41+
build:
42+
needs:
43+
- verify-tag
44+
uses: ./.github/workflows/build.yml
45+
secrets: inherit
46+
with:
47+
build_arch: 'all'
48+
49+
release:
50+
needs:
51+
- verify-tag
52+
- build
53+
runs-on: ubuntu-latest
54+
permissions:
55+
contents: write
56+
env:
57+
GITHUB_TOKEN: ${{ github.token }}
58+
TAG_NAME: ${{ needs.verify-tag.outputs.tag_name }}
59+
steps:
60+
- name: Validate GitHub token
61+
run: |
62+
if [ -z "${GITHUB_TOKEN}" ]; then
63+
echo "Please set GITHUB_TOKEN in the environment to perform a release"
64+
exit 1
65+
fi
66+
- uses: actions/checkout@v6
67+
- name: Download package artifacts
68+
uses: actions/download-artifact@v7
69+
with:
70+
pattern: packages-*
71+
path: ${{ env.BUILD_PACKAGES }}
72+
- name: Moving packages out of folders
73+
run: |
74+
pushd ${{ env.BUILD_PACKAGES }}
75+
find . -mindepth 2 -type f -exec mv -t . {} +
76+
find . -mindepth 1 -maxdepth 1 -type d -exec rm -r {} +
77+
popd
78+
ls -R ${{ env.BUILD_PACKAGES }}
79+
80+
- name: Create draft release
81+
if: startsWith(github.ref, 'refs/tags')
82+
run: |
83+
RNOTES=$(./tools/build/get_release_note.sh --release-tag ${TAG_NAME})
84+
gh release create "${TAG_NAME}" --draft --title "${TAG_NAME}" --repo open-telemetry/opentelemetry-php-distro \
85+
--notes "${RNOTES}" \
86+
build/packages/*.*
87+
- name: Verify sha512 sums
88+
if: startsWith(github.ref, 'refs/tags')
89+
run: |
90+
mkdir -p packages_downloaded_from_github
91+
pushd packages_downloaded_from_github
92+
for attempt in $(seq 1 3); do
93+
gh release download "${TAG_NAME}" && break || (echo "Download draft release assets attempt ${attempt}/3 failed. Waiting 60s." && sleep 60)
94+
done
95+
ls -l .
96+
echo "Verifying that downloaded artifacts pass the downloaded checksums..."
97+
sha512sum --check ./*.sha512
98+
popd
99+
100+
sort "${BUILD_PACKAGES}/"*.sha512 > original_artifacts.sha512
101+
sort "packages_downloaded_from_github/"*.sha512 > downloaded_artifacts.sha512
102+
103+
cat original_artifacts.sha512
104+
cat downloaded_artifacts.sha512
105+
106+
echo "Verifying that original and downloaded artifacts have the same checksums..."
107+
diff original_artifacts.sha512 downloaded_artifacts.sha512 || exit 1
108+
- name: Publish release
109+
if: startsWith(github.ref, 'refs/tags')
110+
run: gh release edit "${TAG_NAME}" --draft=false

DEVELOPMENT.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,28 @@ instead of the usual `composer update`
171171

172172
3) Commit the changes to the composer's lock files
173173

174+
## Making a release
175+
176+
Release process:
177+
178+
1. Prepare and merge a PR that:
179+
- updates project version in [project.properties](project.properties) (`version=...`),
180+
- updates release notes in [docs/release-notes/index.md](docs/release-notes/index.md).
181+
182+
To make release notes preparation easier, you can generate a draft with:
183+
184+
```bash
185+
./tools/prerelease/generate_changelog_draft.sh --previous-release-tag <previous-release-tag>
186+
```
187+
188+
2. After PR is merged to `main`, create a release tag and push it to upstream:
189+
190+
```bash
191+
VERSION=$(grep '^version=' project.properties | cut -d'=' -f2)
192+
git tag "v${VERSION}"
193+
git push upstream "v${VERSION}"
194+
```
195+
196+
Notes:
197+
- Tag must match `project.properties` version exactly in `v<version>` format (for example `v1.2.3`).
198+
- Pushing the tag triggers the release workflow.

docs/release-notes/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.1.0
2+
3+
Initial alpha release.

tools/build/get_release_note.sh

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/bin/bash
2+
3+
CHANGELOG_FILE="docs/release-notes/index.md"
4+
5+
show_help() {
6+
echo "Usage: $0 --release-tag <tag> [--changelog-file <file>]"
7+
echo
8+
echo "Options:"
9+
echo " --release-tag The current release tag (e.g., 1.0.0)."
10+
echo " --changelog-file Path to the changelog file (default: docs/release-notes/index.md)."
11+
echo " -h, --help Display this help message."
12+
}
13+
14+
parse_arguments() {
15+
while [[ "$#" -gt 0 ]]; do
16+
case $1 in
17+
--release-tag)
18+
if [[ -z "$2" ]]; then
19+
echo "Error: --release-tag requires a value."
20+
show_help
21+
exit 1
22+
fi
23+
RELEASE_TAG="$2"
24+
shift 2
25+
;;
26+
--changelog-file)
27+
if [[ -z "$2" ]]; then
28+
echo "Error: --changelog-file requires a value."
29+
show_help
30+
exit 1
31+
fi
32+
CHANGELOG_FILE="$2"
33+
shift 2
34+
;;
35+
-h|--help)
36+
show_help
37+
exit 0
38+
;;
39+
*)
40+
echo "Unknown option: $1"
41+
show_help
42+
exit 1
43+
;;
44+
esac
45+
done
46+
47+
if [[ -z "$RELEASE_TAG" ]]; then
48+
echo "Error: --release-tag is required."
49+
show_help
50+
exit 1
51+
fi
52+
53+
# Remove 'v' prefix if present for compatibility
54+
RELEASE_TAG="${RELEASE_TAG#v}"
55+
}
56+
57+
find_previous_release_tag() {
58+
local release_tag="$1"
59+
local changelog_file="$2"
60+
61+
# Extract version numbers, ignoring the anchor tags
62+
grep -E "^## [0-9]+\.[0-9]+\.[0-9]+" "$changelog_file" | sed 's/^## \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/' | sort -rV | grep -A 1 "^$release_tag" | tail -n 1
63+
}
64+
65+
extract_release_notes() {
66+
local release_tag="$1"
67+
local changelog_file="$2"
68+
local release_section=""
69+
local in_section=0
70+
local next_section_found=0
71+
72+
while IFS= read -r line; do
73+
# Check if we've found a new version section with anchor
74+
if [[ "$line" =~ ^##\ ([0-9]+\.[0-9]+\.[0-9]+) ]]; then
75+
current_version="${BASH_REMATCH[1]}"
76+
77+
# If we found our target version
78+
if [[ "$current_version" == "$release_tag" ]]; then
79+
in_section=1
80+
# Include the full heading with anchor tag
81+
release_section+="$line\n"
82+
continue
83+
# If we were in our target section and found the next version
84+
elif [[ $in_section -eq 1 ]]; then
85+
next_section_found=1
86+
break
87+
fi
88+
fi
89+
90+
# If we're in the target section, add the line to our collection
91+
if [[ $in_section -eq 1 ]]; then
92+
release_section+="$line\n"
93+
fi
94+
done < "$changelog_file"
95+
96+
# If we never found our section, return empty
97+
if [[ $in_section -eq 0 ]]; then
98+
echo ""
99+
return
100+
fi
101+
102+
# Remove trailing newline
103+
release_section=${release_section%\\n}
104+
echo -e "$release_section"
105+
}
106+
107+
main() {
108+
parse_arguments "$@"
109+
110+
if [[ ! -f "$CHANGELOG_FILE" ]]; then
111+
echo "Error: Changelog file '$CHANGELOG_FILE' not found."
112+
exit 1
113+
fi
114+
115+
PREVIOUS_TAG=$(find_previous_release_tag "$RELEASE_TAG" "$CHANGELOG_FILE")
116+
117+
RELEASE_NOTES=$(extract_release_notes "$RELEASE_TAG" "$CHANGELOG_FILE")
118+
119+
if [[ -z "$RELEASE_NOTES" ]]; then
120+
# echo "Error: No release notes found for tag '$RELEASE_TAG'."
121+
# exit 1
122+
exit 0
123+
fi
124+
125+
echo "$RELEASE_NOTES"
126+
127+
if [ "${PREVIOUS_TAG}" != "${RELEASE_TAG}" ] && [ ! -z "${PREVIOUS_TAG}" ]; then
128+
# For GitHub links, prepend 'v' if not present
129+
GITHUB_PREVIOUS_TAG="${PREVIOUS_TAG}"
130+
GITHUB_RELEASE_TAG="${RELEASE_TAG}"
131+
if [[ ! "$GITHUB_PREVIOUS_TAG" =~ ^v ]]; then
132+
GITHUB_PREVIOUS_TAG="v$GITHUB_PREVIOUS_TAG"
133+
fi
134+
if [[ ! "$GITHUB_RELEASE_TAG" =~ ^v ]]; then
135+
GITHUB_RELEASE_TAG="v$GITHUB_RELEASE_TAG"
136+
fi
137+
echo -e "\nFull changelog: [${GITHUB_PREVIOUS_TAG}...${GITHUB_RELEASE_TAG}](https://github.com/open-telemetry/opentelemetry-php-distro/compare/${GITHUB_PREVIOUS_TAG}...${GITHUB_RELEASE_TAG})"
138+
fi
139+
}
140+
141+
main "$@"

0 commit comments

Comments
 (0)