patch | stable | develop | @Dwlad90 #78
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Release | |
run-name: | |
${{ inputs.type }} | ${{ github.event.inputs.prerelease == 'true' && format('{0}', | |
inputs.prerelease-type) || 'stable' }} | ${{ github.ref_name }} | @${{ github.actor }} | |
on: | |
workflow_dispatch: | |
inputs: | |
type: | |
description: 'Release tag' | |
required: true | |
type: choice | |
options: | |
# - 'major' | |
- 'minor' | |
- 'patch' | |
default: 'patch' | |
prerelease: | |
description: 'Is this a prerelease?' | |
type: boolean | |
default: false | |
prerelease-type: | |
description: 'Prerelease tag' | |
required: false | |
type: string | |
concurrency: | |
group: ${{ github.workflow }} | |
cancel-in-progress: true | |
jobs: | |
inputs-validation: | |
name: Validate inputs | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🧪 Validate inputs | |
id: validate | |
run: | | |
if [ "${{ github.event.inputs.prerelease }}" = "true" ] && [ -z "${{ github.event.inputs.prerelease-type }}" ]; then | |
echo "Error: prerelease-type is required when prerelease is checked" | |
exit 1 | |
fi | |
if [ "${{ github.event.inputs.prerelease }}" = "false" ] && [ ! -z "${{ github.event.inputs.prerelease-type }}" ]; then | |
echo "Error: prerelease-type is not allowed when prerelease is not checked" | |
exit 1 | |
fi | |
echo "All inputs are valid" | |
calculate-version: | |
name: Calculate version | |
runs-on: ubuntu-latest | |
needs: inputs-validation | |
outputs: | |
new_version: ${{ steps.calculate.outputs.new_version }} | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: 🔄 Check if can be fast-forwarded to develop | |
run: | | |
# Skip check if on develop | |
if [ "${{ github.ref_name }}" = "develop" ]; then | |
echo "✅ On develop branch, skipping rebase check" | |
exit 0 | |
fi | |
# Fetch both branches | |
git fetch origin develop | |
# Get latest commits | |
current_commit=$(git rev-parse HEAD) | |
develop_commit=$(git rev-parse origin/develop) | |
# Get merge base | |
merge_base=$(git merge-base $current_commit $develop_commit) | |
# Check if current branch is behind develop | |
if [ "$merge_base" != "$develop_commit" ]; then | |
echo "::error::Branch is behind develop. Please rebase first." | |
exit 1 | |
fi | |
# Check if fast-forward is possible | |
if ! git merge-tree $merge_base $develop_commit $current_commit | grep -q "^changed in both"; then | |
echo "✅ Branch can be fast-forwarded to develop" | |
else | |
echo "::error::Branch has conflicts with develop. Please resolve conflicts first." | |
exit 1 | |
fi | |
- name: 🔍 Find previous version tag | |
id: previoustag | |
run: | | |
regex='^[0-9]+\.[0-9]+\.[0-9]+$' | |
previousTag=$(git tag --list | grep -E "$regex" | sort -V | tail -n 1) | |
echo "previousTag=${previousTag}" | |
echo "previousTag=${previousTag}" >> $GITHUB_OUTPUT | |
- name: 🧮 Calculate new version | |
id: calculate | |
run: | | |
. ./scripts/functions.sh | |
previousTag=${{ steps.previoustag.outputs.previousTag }} | |
if [ -z "$previousTag" ]; then | |
previousTag="0.0.0" | |
fi | |
if [ "${{ github.event.inputs.prerelease }}" = "true" ]; then | |
newVersion=$(increment_version "$previousTag" "${{ github.event.inputs.type }}" "${{ github.event.inputs.prerelease-type }}") | |
else | |
newVersion=$(increment_version "$previousTag" "${{ github.event.inputs.type }}") | |
fi | |
echo "Next version: $newVersion" | |
echo "new_version=$newVersion" >> $GITHUB_OUTPUT | |
pre-release: | |
name: Prepare release ${{ needs.calculate-version.outputs.new_version }} | |
needs: calculate-version | |
environment: | |
name: release-approval | |
env: | |
HUSKY_SKIP_HOOKS: 1 | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Git configure | |
uses: ./.github/actions/gitconfig | |
- name: 🔧 Bump version | |
run: ./scripts/git/bump-version.sh ${{ needs.calculate-version.outputs.new_version }} | |
- name: 🛠️ Setup environment | |
uses: ./.github/actions/setup | |
- name: 🔄 Update Cargo lock | |
run: | | |
cargo update --workspace | |
- name: 📝 Commit version bump | |
id: commit | |
run: | | |
git add . | |
git commit --no-verify -m "Bump version to ${{ needs.calculate-version.outputs.new_version }}" | |
git log --oneline | head -n 3 | |
- name: ✅ Check if tag can be fast-forwarded | |
id: ff_check | |
run: | | |
git fetch --all --tags | |
# Get the merge base between current HEAD and master | |
merge_base=$(git merge-base HEAD origin/master) | |
master_commit=$(git rev-parse origin/master) | |
# Check if HEAD is ahead of or equal to master | |
if [ "$merge_base" = "$master_commit" ]; then | |
echo "Tag can be fast-forwarded to master" | |
echo "can_ff=true" >> $GITHUB_OUTPUT | |
else | |
echo "Error: Current HEAD cannot be fast-forwarded to master" | |
echo "can_ff=false" >> $GITHUB_OUTPUT | |
exit 1 | |
fi | |
- name: 🏷️ Create new version tag | |
id: newtag | |
if: steps.ff_check.outputs.can_ff == 'true' | |
run: | | |
newVersion=${{ needs.calculate-version.outputs.new_version }} | |
if git rev-parse "$newVersion" >/dev/null 2>&1; then | |
git tag -d "$newVersion" | |
git push --delete origin "$newVersion" | |
fi | |
git tag $newVersion -m "Release $newVersion" | |
git push origin $newVersion | |
release-draft: | |
name: Draft release ${{ needs.calculate-version.outputs.new_version }} | |
needs: [pre-release, calculate-version] | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Git configure | |
uses: ./.github/actions/gitconfig | |
- name: 🔀 Checkout to ${{ needs.calculate-version.outputs.new_version }} | |
run: | | |
git checkout ${{ needs.calculate-version.outputs.new_version }} | |
- name: 🚀 Create Release | |
uses: softprops/action-gh-release@v2 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
prerelease: ${{ github.event.inputs.prerelease }} | |
generate_release_notes: true | |
draft: true | |
fail_on_unmatched_files: true | |
tag_name: ${{ needs.calculate-version.outputs.new_version }} | |
target_commitish: ${{ github.sha }} | |
name: ${{ needs.calculate-version.outputs.new_version }} | |
upload-npm: | |
name: Upload ${{ needs.calculate-version.outputs.new_version }} version to NPM | |
needs: [release-draft, calculate-version] | |
runs-on: ubuntu-latest | |
environment: | |
name: changlog-approval | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Git configure | |
uses: ./.github/actions/gitconfig | |
- name: 🔀 Checkout to ${{ needs.calculate-version.outputs.new_version }} | |
run: | | |
git checkout ${{ needs.calculate-version.outputs.new_version }} | |
- name: 📦 Publish to NPM | |
id: npm | |
run: | | |
MAX_ATTEMPTS=100 | |
SLEEP_BASE=5 | |
run_id=$(gh workflow run npm.yml \ | |
--ref ${{ needs.calculate-version.outputs.new_version }} \ | |
--repo ${{ github.repository }}) || exit 1 | |
for i in $(seq 1 $MAX_ATTEMPTS); do | |
wait_time=$(( SLEEP_BASE * i )) | |
echo "Waiting for $wait_time seconds before checking the status" | |
sleep "$wait_time" | |
run_id=$(gh run list \ | |
--workflow=npm.yml \ | |
--limit=5 \ | |
--json databaseId,status \ | |
-q 'map(select(.status == "in_progress" or .status == "queued" or .status == "waiting")) | .[0].databaseId') | |
if [ ! -z "$run_id" ]; then | |
break | |
fi | |
done | |
if [ -z "$run_id" ]; then | |
echo "Error: Failed to get run ID" | |
exit 1 | |
fi | |
SLEEP_BASE=$((60*20)) | |
echo "Sleeping for $((SLEEP_BASE/60)) minutes before checking the status" | |
sleep $SLEEP_BASE # Wait before checking the status | |
while true; do | |
status=$(gh run view "$run_id" --json status --jq '.status') | |
echo "Current status: $status" | |
case $status in | |
"completed") | |
conclusion=$(gh run view "$run_id" --json conclusion --jq '.conclusion') | |
if [ "$conclusion" = "success" ]; then | |
echo "✅ Workflow completed successfully" | |
exit 0 | |
else | |
echo "::error::Workflow failed with conclusion: $conclusion" | |
exit 1 | |
fi | |
;; | |
"in_progress"|"queued"|"waiting") | |
sleep 60 # Wait for 1 minute | |
;; | |
*) | |
echo "::error::Unexpected status: $status" | |
exit 1 | |
;; | |
esac | |
done | |
status=$(gh run view "$run_id" --json status --jq '.status') | |
if [ "$status" != "completed" ] || [ "$status" = "failure" ] || [ "$status" = "cancelled" ]; then | |
echo "Workflow failed with status: $status" | |
exit 1 | |
fi | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
release: | |
name: Release ${{ needs.calculate-version.outputs.new_version }} | |
needs: [upload-npm, calculate-version] | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: 📢 Update Release Status | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
if ! gh release view ${{ needs.calculate-version.outputs.new_version }}; then | |
echo "::error::Release not found" | |
exit 1 | |
fi | |
gh release edit ${{ needs.calculate-version.outputs.new_version }} \ | |
--draft=false \ | |
${{ github.event.inputs.prerelease != 'true' && '--latest' || '' }} \ | |
--verify-tag | |
gh release view ${{ needs.calculate-version.outputs.new_version }} \ | |
--json isDraft,tagName,url \ | |
--template '✅ Release {{.tagName}} published: {{.url}}' | |
merge-develop: | |
name: Merge to develop branch | |
needs: [release, calculate-version] | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Git config | |
uses: ./.github/actions/gitconfig | |
- name: 🔀 Merge to develop | |
run: | | |
git config --global user.name "${GITHUB_ACTOR}" | |
git config --global user.email "${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com" | |
git checkout develop | |
git merge ${{ needs.calculate-version.outputs.new_version }} | |
git push origin develop | |
merge-master: | |
name: Merge to master branch | |
needs: [merge-develop, calculate-version] | |
runs-on: ubuntu-latest | |
steps: | |
- name: 🛠️ Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Git configure | |
uses: ./.github/actions/gitconfig | |
- name: 🔀 Merge to master | |
run: | | |
git config --global user.name "${GITHUB_ACTOR}" | |
git config --global user.email "${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com" | |
git checkout master | |
git merge --ff-only ${{ needs.calculate-version.outputs.new_version }} | |
git push origin master |