Skip to content

Create Release for git_branches #13

Create Release for git_branches

Create Release for git_branches #13

Workflow file for this run

name: Create Package Release
run-name: Create Release for ${{ inputs.package }}
on:
workflow_dispatch:
inputs:
package:
description: "Package to release"
required: true
default: changelog_cli
type: choice
options:
- changelog_cli
- slack_cli
- disk_analyzer_cli
- git_chain
- git_branches
dry_run:
description: "Dry run (do not create tag/release)"
required: false
default: false
type: boolean
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
package_dir: ${{ steps.package_config.outputs.package_dir }}
executable_name: ${{ steps.package_config.outputs.executable_name }}
build_mode: ${{ steps.package_config.outputs.build_mode }}
build_matrix: ${{ steps.package_config.outputs.build_matrix }}
tag_name: ${{ steps.tag_check.outputs.tag_name }}
version: ${{ steps.version_pubspec.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
# Use a PAT so the pushed tag triggers the publish.yaml workflow.
# Tags pushed with the default GITHUB_TOKEN do not trigger workflows.
# Falls back to GITHUB_TOKEN if RELEASE_PAT is not configured (tag
# push then won't auto-publish to pub.dev).
token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }}
- name: Setup Dart
uses: dart-lang/setup-dart@v1
- name: Install and activate changelog_cli
run: |
cd changelog_cli
dart pub get
dart pub global activate --source=path .
- name: Resolve package configuration
id: package_config
run: |
PACKAGE="${{ inputs.package }}"
case "$PACKAGE" in
changelog_cli)
echo "package_dir=changelog_cli" >> "$GITHUB_OUTPUT"
echo "executable_name=changelog_cli" >> "$GITHUB_OUTPUT"
echo "build_mode=exe" >> "$GITHUB_OUTPUT"
echo 'build_matrix={"include":[{"os":"ubuntu-latest","artifact_name":"changelog_cli_linux","binary_name":"changelog_cli_linux"},{"os":"windows-latest","artifact_name":"changelog_cli_windows_x64","binary_name":"changelog_cli.exe"},{"os":"macos-latest","artifact_name":"changelog_cli_macos_arm64","binary_name":"changelog_cli_macos"}]}' >> "$GITHUB_OUTPUT"
;;
slack_cli)
echo "package_dir=slack_cli" >> "$GITHUB_OUTPUT"
echo "executable_name=slack_cli" >> "$GITHUB_OUTPUT"
echo "build_mode=exe" >> "$GITHUB_OUTPUT"
echo 'build_matrix={"include":[{"os":"ubuntu-latest","artifact_name":"slack_cli_linux","binary_name":"slack_cli_linux"},{"os":"windows-latest","artifact_name":"slack_cli_windows_x64","binary_name":"slack_cli.exe"},{"os":"macos-latest","artifact_name":"slack_cli_macos_arm64","binary_name":"slack_cli_macos"}]}' >> "$GITHUB_OUTPUT"
;;
disk_analyzer_cli)
echo "package_dir=disk_analyzer_cli" >> "$GITHUB_OUTPUT"
echo "executable_name=disk_analyzer_cli" >> "$GITHUB_OUTPUT"
echo "build_mode=bundle" >> "$GITHUB_OUTPUT"
echo 'build_matrix={"include":[{"os":"ubuntu-latest","artifact_name":"disk_analyzer_cli_linux_x64"},{"os":"windows-latest","artifact_name":"disk_analyzer_cli_windows_x64"},{"os":"macos-latest","artifact_name":"disk_analyzer_cli_macos_arm64"}]}' >> "$GITHUB_OUTPUT"
;;
git_chain)
echo "package_dir=git_chain" >> "$GITHUB_OUTPUT"
echo "executable_name=git_chain" >> "$GITHUB_OUTPUT"
echo "build_mode=bundle" >> "$GITHUB_OUTPUT"
echo "changelog_printer=markdown" >> "$GITHUB_OUTPUT"
echo 'build_matrix={"include":[{"os":"ubuntu-latest","artifact_name":"git_chain_linux_x64"},{"os":"windows-latest","artifact_name":"git_chain_windows_x64"},{"os":"macos-latest","artifact_name":"git_chain_macos_arm64"}]}' >> "$GITHUB_OUTPUT"
;;
git_branches)
echo "package_dir=git_branches" >> "$GITHUB_OUTPUT"
echo "executable_name=git_branches" >> "$GITHUB_OUTPUT"
echo "build_mode=exe" >> "$GITHUB_OUTPUT"
echo "changelog_printer=markdown" >> "$GITHUB_OUTPUT"
echo 'build_matrix={"include":[{"os":"ubuntu-latest","artifact_name":"git_branches_linux","binary_name":"git_branches_linux"},{"os":"windows-latest","artifact_name":"git_branches_windows_x64","binary_name":"git_branches.exe"},{"os":"macos-latest","artifact_name":"git_branches_macos_arm64","binary_name":"git_branches_macos"}]}' >> "$GITHUB_OUTPUT"
;;
esac
- name: Read version from pubspec.yaml
id: version_pubspec
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION=$(grep '^version:' "$PACKAGE_DIR/pubspec.yaml" | sed 's/version: //')
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Version from pubspec.yaml: $VERSION"
- name: Read version from version.dart if present
id: version_dart
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION_FILE="$PACKAGE_DIR/lib/src/version.dart"
if [ -f "$VERSION_FILE" ]; then
VERSION=$(grep 'const packageVersion' "$VERSION_FILE" | sed "s/const packageVersion = '\(.*\)';/\1/")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Version from version.dart: $VERSION"
else
echo 'version=' >> "$GITHUB_OUTPUT"
echo "No version.dart for $PACKAGE_DIR, using pubspec.yaml only"
fi
- name: Verify versions match
run: |
if [ -n "${{ steps.version_dart.outputs.version }}" ] && [ "${{ steps.version_dart.outputs.version }}" != "${{ steps.version_pubspec.outputs.version }}" ]; then
echo "ERROR: Version mismatch!"
echo "version.dart: ${{ steps.version_dart.outputs.version }}"
echo "pubspec.yaml: ${{ steps.version_pubspec.outputs.version }}"
exit 1
fi
echo "✅ Release version: ${{ steps.version_pubspec.outputs.version }}"
- name: Get latest tag
id: latest_tag
run: |
PACKAGE="${{ inputs.package }}"
LATEST_TAG=$(git tag -l "$PACKAGE-v*" | sort -V | tail -n 1)
if [ -z "$LATEST_TAG" ]; then
echo "No previous tags found for $PACKAGE, using initial commit"
LATEST_TAG=$(git rev-list --max-parents=0 HEAD)
fi
echo "latest_tag=$LATEST_TAG" >> "$GITHUB_OUTPUT"
echo "Latest tag: $LATEST_TAG"
- name: Check if tag already exists
id: tag_check
run: |
TAG_NAME="${{ inputs.package }}-v${{ steps.version_pubspec.outputs.version }}"
if git tag -l | grep -q "^$TAG_NAME$"; then
echo 'exists=true' >> "$GITHUB_OUTPUT"
echo "❌ Tag $TAG_NAME already exists"
else
echo 'exists=false' >> "$GITHUB_OUTPUT"
echo "✅ Tag $TAG_NAME does not exist"
fi
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
- name: Fail if tag exists
if: steps.tag_check.outputs.exists == 'true'
run: |
echo "ERROR: Tag ${{ steps.tag_check.outputs.tag_name }} already exists!"
echo "Please update the version before releasing ${{ inputs.package }}"
exit 1
- name: Check if version already in CHANGELOG.md
id: changelog_present
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION="${{ steps.version_pubspec.outputs.version }}"
CHANGELOG="$PACKAGE_DIR/CHANGELOG.md"
present=false
if [ -f "$CHANGELOG" ] && awk -v ver="$VERSION" '
{ s=$0; sub(/^#+[[:space:]]*/,"",s); sub(/[[:space:]]+$/,"",s); if (s==ver) { found=1; exit } }
END { exit (found ? 0 : 1) }
' "$CHANGELOG"; then
present=true
echo "ℹ️ Version $VERSION already present in $CHANGELOG, skipping changelog generation"
else
echo "✅ Version $VERSION not yet in $CHANGELOG, will generate"
fi
echo "present=$present" >> "$GITHUB_OUTPUT"
- name: Generate changelog and update CHANGELOG.md
id: changelog
if: steps.changelog_present.outputs.present != 'true'
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION="${{ steps.version_pubspec.outputs.version }}"
PRINTER="${{ steps.package_config.outputs.changelog_printer }}"
PRINTER="${PRINTER:-simple}"
echo "Generating changelog for $PACKAGE_DIR from ${{ steps.latest_tag.outputs.latest_tag }} to HEAD (printer: $PRINTER)"
changelog_cli generate \
--start "${{ steps.latest_tag.outputs.latest_tag }}" \
--end HEAD \
--path "$PACKAGE_DIR" \
--version "$VERSION" \
--printer "$PRINTER" \
--output "$PACKAGE_DIR/CHANGELOG.md"
changelog_cli generate \
--start "${{ steps.latest_tag.outputs.latest_tag }}" \
--end HEAD \
--path "$PACKAGE_DIR" \
--version "$VERSION" \
--printer "$PRINTER" \
--output /tmp/new_changelog.md
echo "✅ Updated $PACKAGE_DIR/CHANGELOG.md with version $VERSION"
- name: Extract existing changelog section for release notes
if: steps.changelog_present.outputs.present == 'true'
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION="${{ steps.version_pubspec.outputs.version }}"
CHANGELOG="$PACKAGE_DIR/CHANGELOG.md"
# Extract the section for VERSION: from its header line up to the
# next version header (a line whose text after stripping leading
# '#'s starts with a version number).
awk -v ver="$VERSION" '
function header_version(line, s) {
s=line; sub(/^#+[[:space:]]*/,"",s); sub(/[[:space:]]+$/,"",s)
return s
}
!found {
if (header_version($0)==ver) { found=1; print; next }
}
found {
s=header_version($0)
if (s ~ /^[0-9]+\.[0-9]+/) { exit }
print
}
' "$CHANGELOG" > /tmp/new_changelog.md
echo "✅ Extracted existing CHANGELOG.md section for version $VERSION"
echo "📝 Release notes content:"
cat /tmp/new_changelog.md
- name: Setup Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Commit updated CHANGELOG.md
run: |
PACKAGE_DIR="${{ steps.package_config.outputs.package_dir }}"
VERSION="${{ steps.version_pubspec.outputs.version }}"
git add "$PACKAGE_DIR/CHANGELOG.md"
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore($PACKAGE_DIR): update CHANGELOG.md for v$VERSION"
echo "✅ Committed CHANGELOG.md changes"
fi
- name: Push changes
if: ${{ !inputs.dry_run }}
run: git push origin main
- name: Create and push tag
if: ${{ !inputs.dry_run }}
run: |
TAG_NAME="${{ steps.tag_check.outputs.tag_name }}"
git tag -a "$TAG_NAME" -m "Release $TAG_NAME"
git push origin "$TAG_NAME"
echo "✅ Created and pushed tag: $TAG_NAME"
- name: Create GitHub Release
if: ${{ !inputs.dry_run }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ steps.tag_check.outputs.tag_name }}"
gh release create "$TAG_NAME" \
--title "$TAG_NAME" \
--notes-file /tmp/new_changelog.md \
--draft
echo "✅ Created GitHub release: $TAG_NAME"
echo "The release is created as draft and will be published after artifacts are uploaded"
- name: Dry run summary
if: ${{ inputs.dry_run }}
run: |
echo "🔍 DRY RUN SUMMARY:"
echo "- Package: ${{ steps.package_config.outputs.package_dir }}"
echo "- Version: ${{ steps.version_pubspec.outputs.version }}"
echo "- Tag that would be created: ${{ steps.tag_check.outputs.tag_name }}"
echo "- Latest tag found: ${{ steps.latest_tag.outputs.latest_tag }}"
if [ "${{ steps.changelog_present.outputs.present }}" == "true" ]; then
echo "- Version already in CHANGELOG.md, generation skipped (existing section used for release notes)"
else
echo "- CHANGELOG.md would be updated with new content"
fi
echo "- No actual tag or release would be created"
echo ""
echo "📝 Release notes content:"
cat /tmp/new_changelog.md
build_assets:
needs: release
if: ${{ !inputs.dry_run }}
runs-on: ${{ matrix.os }}
strategy:
matrix: ${{ fromJson(needs.release.outputs.build_matrix) }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Dart
uses: dart-lang/setup-dart@v1
- name: Install dependencies
run: |
cd "${{ needs.release.outputs.package_dir }}"
dart pub get
- name: Build executable
if: ${{ needs.release.outputs.build_mode == 'exe' }}
run: |
cd "${{ needs.release.outputs.package_dir }}"
mkdir -p "build/${{ matrix.artifact_name }}"
dart compile exe "bin/${{ needs.release.outputs.executable_name }}.dart" -o "build/${{ matrix.artifact_name }}/${{ matrix.binary_name }}"
- name: Upload executable artifact
if: ${{ needs.release.outputs.build_mode == 'exe' }}
uses: actions/upload-artifact@v7
with:
name: asset-${{ matrix.artifact_name }}
path: ${{ needs.release.outputs.package_dir }}/build/${{ matrix.artifact_name }}/${{ matrix.binary_name }}
- name: Build CLI bundle
if: ${{ needs.release.outputs.build_mode == 'bundle' }}
run: |
cd "${{ needs.release.outputs.package_dir }}"
dart build cli --target "bin/${{ needs.release.outputs.executable_name }}.dart" --output "build/${{ matrix.artifact_name }}"
- name: Upload bundle artifact
if: ${{ needs.release.outputs.build_mode == 'bundle' }}
uses: actions/upload-artifact@v7
with:
name: asset-${{ matrix.artifact_name }}
path: ${{ needs.release.outputs.package_dir }}/build/${{ matrix.artifact_name }}/bundle
upload_artifacts:
needs: [release, build_assets]
if: ${{ !inputs.dry_run }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
pattern: asset-*
- name: Package release bundles
if: ${{ needs.release.outputs.build_mode == 'bundle' }}
run: |
mkdir -p dist
for bundle_dir in release-assets/asset-*; do
asset_name="${bundle_dir#release-assets/asset-}"
(
cd "$bundle_dir"
zip -r "../../dist/${asset_name}.zip" bin lib
)
done
- name: Upload executable artifacts to existing release
if: ${{ needs.release.outputs.build_mode == 'exe' }}
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.release.outputs.tag_name }}
files: release-assets/asset-*/*
draft: false
- name: Upload bundle archives to existing release
if: ${{ needs.release.outputs.build_mode == 'bundle' }}
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.release.outputs.tag_name }}
files: dist/*.zip
draft: false
update_homebrew:
# Runs after the release is published with its assets, since the tap's
# update workflow downloads the release binaries to recompute checksums.
needs: [release, upload_artifacts]
if: ${{ !inputs.dry_run }}
runs-on: ubuntu-latest
steps:
- name: Trigger homebrew formula update
env:
# Needs actions:write on orestesgaolin/homebrew-tap.
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
run: |
PACKAGE="${{ inputs.package }}"
case "$PACKAGE" in
changelog_cli) WORKFLOW=update-changelog-cli.yml ;;
slack_cli) WORKFLOW=update-slack-cli.yml ;;
disk_analyzer_cli) WORKFLOW=update-disk-analyzer-cli.yml ;;
git_chain) WORKFLOW=update-git-chain.yml ;;
git_branches) WORKFLOW=update-git-branches.yml ;;
*)
echo "No homebrew formula for $PACKAGE, skipping"
exit 0
;;
esac
if [ -z "$GH_TOKEN" ]; then
echo "::warning::RELEASE_PAT not set; skipping homebrew update for $PACKAGE"
exit 0
fi
echo "Dispatching $WORKFLOW in orestesgaolin/homebrew-tap"
gh workflow run "$WORKFLOW" --repo orestesgaolin/homebrew-tap --ref main