name: Release run-name: "Release ${{ github.event.inputs.tag || github.ref_name }}" on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Tag to release (e.g. v0.1.0)' required: true jobs: test: name: Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Vet run: go vet ./... - name: Test run: go test ./... release: name: Release needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Build release binaries run: | VERSION="${{ github.event.inputs.tag || github.ref_name }}" for target in "linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64" "windows/amd64"; do GOOS="${target%/*}" GOARCH="${target#*/}" EXT="" [ "$GOOS" = "windows" ] && EXT=".exe" NAME="pgtidy-${GOOS}-${GOARCH}${EXT}" GOOS="$GOOS" GOARCH="$GOARCH" CGO_ENABLED=0 go build \ -trimpath \ -ldflags "-X main.version=${VERSION}" \ -o "$NAME" ./cmd/pgtidy echo "Built $NAME ($(ls -lh "$NAME" | awk '{print $5}'))" if [ "$GOOS" = "linux" ]; then PKGVER="${VERSION#v}" TARNAME="pgtidy_${PKGVER}_${GOOS}_${GOARCH}.tar.gz" cp "$NAME" pgtidy tar czf "$TARNAME" pgtidy LICENSE rm pgtidy echo "Packed $TARNAME" fi done - name: Create release and upload binaries run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" API="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases" PREV_TAG=$(git tag --sort=-version:refname | { grep -v "^${TAG}$" || true; } | head -1) if [ -n "$PREV_TAG" ] && git rev-parse --verify "${PREV_TAG}" >/dev/null 2>&1; then NOTES=$(git log "${PREV_TAG}..${TAG}" --pretty=format:"- %s" --no-merges) else NOTES=$(git log --pretty=format:"- %s" --no-merges) fi BODY="## What's changed"$'\n'"${NOTES}" BODY_JSON=$(printf '%s' "$BODY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))') echo "Creating release ${TAG} via ${API}..." RELEASE=$(curl -s -X POST "$API" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\",\"body\":${BODY_JSON}}") echo "API response: $RELEASE" UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') if [ -z "$UPLOAD_URL" ]; then echo "upload_url not found in response — aborting" exit 1 fi for f in pgtidy-* pgtidy_*.tar.gz; do echo "Uploading $f..." curl -sf -X POST "${UPLOAD_URL}?name=${f}" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary "@${f}" > /dev/null done env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pkg-deb: name: Debian packages needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Build .deb packages run: | VERSION="${{ github.event.inputs.tag || github.ref_name }}" PKGVER="${VERSION#v}" for GOARCH in amd64 arm64; do GOOS=linux GOARCH=$GOARCH CGO_ENABLED=0 go build \ -trimpath \ -ldflags "-X main.version=${PKGVER}" \ -o pgtidy ./cmd/pgtidy PKGDIR="pgtidy_${PKGVER}_${GOARCH}" mkdir -p "${PKGDIR}/DEBIAN" "${PKGDIR}/usr/bin" install -m755 pgtidy "${PKGDIR}/usr/bin/pgtidy" sed -e "s/VERSION/${PKGVER}/" -e "s/ARCH/${GOARCH}/" \ linux/debian/control > "${PKGDIR}/DEBIAN/control" dpkg-deb --build --root-owner-group "${PKGDIR}" echo "Built ${PKGDIR}.deb" rm -rf "${PKGDIR}" pgtidy done - name: Upload to release run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ -H "Authorization: token ${GITHUB_TOKEN}") UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') [ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; } for f in *.deb; do echo "Uploading $(basename "$f")..." curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/vnd.debian.binary-package" \ --data-binary "@${f}" > /dev/null done env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pkg-rpm: name: RPM package needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Build RPM run: | set -euo pipefail VERSION="${{ github.event.inputs.tag || github.ref_name }}" PKGVER="${VERSION#v}" sudo apt-get update -y sudo apt-get install -y rpm CGO_ENABLED=0 go build \ -trimpath \ -ldflags "-X main.version=${PKGVER}" \ -o pgtidy \ ./cmd/pgtidy sed -i "s/^Version:.*/Version: ${PKGVER}/" linux/centos/pgtidy.spec mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} cp pgtidy ~/rpmbuild/SOURCES/pgtidy cp LICENSE ~/rpmbuild/SOURCES/LICENSE cp linux/centos/pgtidy.spec ~/rpmbuild/SPECS/ rpmbuild --nodeps -bb ~/rpmbuild/SPECS/pgtidy.spec mkdir -p rpm-out find ~/rpmbuild/RPMS/ -name '*.rpm' -exec cp {} rpm-out/ \; - name: Upload to release run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ -H "Authorization: token ${GITHUB_TOKEN}") UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') [ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; } while IFS= read -r f; do echo "Uploading $(basename "$f")..." curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/x-rpm" \ --data-binary "@${f}" > /dev/null done < <(find rpm-out -name "*.rpm") env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pkg-nsis: name: Windows installer needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Build NSIS installer run: | set -euo pipefail VERSION="${{ github.event.inputs.tag || github.ref_name }}" PKGVER="${VERSION#v}" sudo apt-get update -y sudo apt-get install -y nsis GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build \ -trimpath \ -ldflags "-X main.version=${PKGVER}" \ -o pgtidy.exe \ ./cmd/pgtidy makensis -DVERSION="${PKGVER}" -DSRC_EXE="$(pwd)/pgtidy.exe" windows/installer.nsi - name: Upload to release run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ -H "Authorization: token ${GITHUB_TOKEN}") UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') [ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; } for f in windows/pgtidy-setup-*.exe; do echo "Uploading $(basename "$f")..." curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary "@${f}" > /dev/null done env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} pkg-aur: name: AUR package needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Publish to AUR env: AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }} run: | set -euo pipefail VERSION="${{ github.event.inputs.tag || github.ref_name }}" PKGVER="${VERSION#v}" AUR_KEY_PATH="$HOME/.ssh/aur" AUR_KNOWN_HOSTS="$HOME/.ssh/known_hosts" mkdir -p ~/.ssh && chmod 700 ~/.ssh if [ -z "${AUR_SSH_KEY:-}" ]; then echo "AUR_SSH_KEY is empty — skipping AUR publish" exit 0 fi CLEAN_AUR_SSH_KEY="$(printf '%s' "$AUR_SSH_KEY" | tr -d '\r')" if printf '%s' "$CLEAN_AUR_SSH_KEY" | grep -q "^-----BEGIN .*PRIVATE KEY-----$"; then printf '%s\n' "$CLEAN_AUR_SSH_KEY" > "$AUR_KEY_PATH" elif printf '%s' "$CLEAN_AUR_SSH_KEY" | grep -q '\\n'; then printf '%b\n' "$CLEAN_AUR_SSH_KEY" > "$AUR_KEY_PATH" else if ! printf '%s' "$CLEAN_AUR_SSH_KEY" | tr -d '[:space:]' | base64 --decode > "$AUR_KEY_PATH" 2>/dev/null; then printf '%s\n' "$CLEAN_AUR_SSH_KEY" > "$AUR_KEY_PATH" fi fi chmod 600 "$AUR_KEY_PATH" if ! ssh-keygen -y -f "$AUR_KEY_PATH" >/dev/null 2>&1; then echo "AUR_SSH_KEY is not a valid private key — skipping AUR publish" exit 0 fi ssh-keyscan -t rsa,ed25519 aur.archlinux.org >> "$AUR_KNOWN_HOSTS" chmod 644 "$AUR_KNOWN_HOSTS" GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$AUR_KNOWN_HOSTS -i $AUR_KEY_PATH" \ git clone ssh://aur@aur.archlinux.org/pgtidy-bin.git aur-repo if [ -f aur-repo/PKGBUILD ]; then CURRENT_PKGVER=$(awk -F= '/^pkgver=/ {print $2; exit}' aur-repo/PKGBUILD | tr -d "[:space:]") CURRENT_PKGREL=$(awk -F= '/^pkgrel=/ {print $2; exit}' aur-repo/PKGBUILD | tr -d "[:space:]") else CURRENT_PKGVER="" CURRENT_PKGREL=0 fi if [ "$CURRENT_PKGVER" = "$PKGVER" ]; then PKGREL=$((CURRENT_PKGREL + 1)) else PKGREL=1 fi echo "Publishing pgtidy-bin ${PKGVER}-${PKGREL} to AUR" SHA_AMD64=$(curl -fsSL "https://git.warky.dev/wdevs/pgtidy/releases/download/v${PKGVER}/pgtidy_${PKGVER}_linux_amd64.tar.gz" | sha256sum | cut -d' ' -f1) SHA_ARM64=$(curl -fsSL "https://git.warky.dev/wdevs/pgtidy/releases/download/v${PKGVER}/pgtidy_${PKGVER}_linux_arm64.tar.gz" | sha256sum | cut -d' ' -f1) sed -e "s/^pkgver=.*/pkgver=${PKGVER}/" \ -e "s/^pkgrel=.*/pkgrel=${PKGREL}/" \ -e "s/^sha256sums_x86_64=.*/sha256sums_x86_64=('${SHA_AMD64}')/" \ -e "s/^sha256sums_aarch64=.*/sha256sums_aarch64=('${SHA_ARM64}')/" \ linux/arch/PKGBUILD > aur-repo/PKGBUILD CID=$(docker run -d archlinux:latest sleep infinity) cleanup_docker() { docker rm -f "$CID" >/dev/null 2>&1 || true; } trap cleanup_docker EXIT docker exec "$CID" mkdir -p /build docker cp aur-repo/PKGBUILD "$CID:/build/PKGBUILD" docker exec "$CID" bash -c " pacman -Sy --noconfirm base-devel && useradd -m builder && chown -R builder:builder /build && runuser -u builder -- bash -c 'cd /build && makepkg --printsrcinfo > .SRCINFO' " docker cp "$CID:/build/.SRCINFO" aur-repo/.SRCINFO trap - EXIT; cleanup_docker cd aur-repo git config user.email "hein@warky.dev" git config user.name "Hein" git add PKGBUILD .SRCINFO git commit -m "Update to v${PKGVER}-${PKGREL}" GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$AUR_KNOWN_HOSTS -i $AUR_KEY_PATH" \ git push origin HEAD:master vscode-package: name: VSCode Extension needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' - uses: pnpm/action-setup@v4 with: version: latest - name: Set version from tag working-directory: editors/vscode run: | TAG="${{ github.event.inputs.tag || github.ref_name }}" npm pkg set version="${TAG#v}" - name: Install and package working-directory: editors/vscode run: | pnpm install --frozen-lockfile pnpm run compile pnpm run package - name: Upload to release run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ -H "Authorization: token ${GITHUB_TOKEN}") UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') [ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; } for f in editors/vscode/*.vsix; do echo "Uploading $(basename "$f")..." curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary "@${f}" > /dev/null done env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} datagrip-package: name: DataGrip Plugin needs: release runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: '21' - name: Set version from tag working-directory: editors/datagrip run: | TAG="${{ github.event.inputs.tag || github.ref_name }}" sed -i "s/^pluginVersion=.*/pluginVersion=${TAG#v}/" gradle.properties - name: Build plugin working-directory: editors/datagrip run: ./gradlew buildPlugin - name: Upload to release run: | set -euo pipefail TAG="${{ github.event.inputs.tag || github.ref_name }}" RELEASE=$(curl -s "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ -H "Authorization: token ${GITHUB_TOKEN}") UPLOAD_URL=$(echo "$RELEASE" | grep -o '"upload_url":"[^"]*"' | cut -d'"' -f4 | sed 's/{[^}]*}//') [ -z "$UPLOAD_URL" ] && { echo "upload_url not found: $RELEASE"; exit 1; } for f in editors/datagrip/build/distributions/*.zip; do echo "Uploading $(basename "$f")..." curl -s -X POST "${UPLOAD_URL}?name=$(basename "$f")" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Content-Type: application/zip" \ --data-binary "@${f}" > /dev/null done env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}