name: Release Tool on: push: tags: - "v*" jobs: release: runs-on: self-hosted env: CHECKOUT_PATH: ${{ vars.SOW_TOOLS_CHECKOUT_PATH }} SOW_TOOLS_REPO_URL: ${{ vars.SOW_TOOLS_REPO_URL }} steps: - name: Sync tools checkout to tag env: TAG_NAME: ${{ github.ref_name }} EVENT_SHA: ${{ github.sha }} GITEA_SERVER_URL: ${{ github.server_url }} GITEA_REPO: ${{ github.repository }} run: | set -euo pipefail CHECKOUT_PATH="${CHECKOUT_PATH:-/home/ubuntu/tools-checkout}" SOW_TOOLS_REPO_URL="${SOW_TOOLS_REPO_URL:-${GITEA_SERVER_URL%/}/${GITEA_REPO}.git}" export GIT_TERMINAL_PROMPT=0 export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh -o BatchMode=yes -o ConnectTimeout=20 -o ServerAliveInterval=10 -o ServerAliveCountMax=3}" if [[ ! -d "${CHECKOUT_PATH}/.git" ]]; then mkdir -p "$(dirname "${CHECKOUT_PATH}")" echo "Cloning tools checkout from ${SOW_TOOLS_REPO_URL} into ${CHECKOUT_PATH}" timeout 120 git clone --filter=blob:none "${SOW_TOOLS_REPO_URL}" "${CHECKOUT_PATH}" fi cd "${CHECKOUT_PATH}" git remote set-url origin "${SOW_TOOLS_REPO_URL}" echo "Fetching tools refs from ${SOW_TOOLS_REPO_URL}" timeout 120 git fetch origin --prune --force --tags TAG_SHA="$(git rev-list -n1 "refs/tags/${TAG_NAME}")" if [[ -n "${EVENT_SHA}" && "${TAG_SHA}" != "${EVENT_SHA}" ]]; then echo "Fetched tag ${TAG_NAME} resolves to ${TAG_SHA}, but the workflow event SHA is ${EVENT_SHA}." echo "Refusing to build a release from a stale or mismatched local tag." exit 1 fi git reset --hard "refs/tags/${TAG_NAME}" git clean -ffdx echo "Release ${TAG_NAME} will build commit $(git rev-parse HEAD)" - name: Build sow-toolkit binaries run: | set -euo pipefail CHECKOUT_PATH="${CHECKOUT_PATH:-/home/ubuntu/tools-checkout}" cd "${CHECKOUT_PATH}" rm -f ./tools/sow-toolkit ./tools/sow-toolkit.exe mkdir -p tools .cache/go-build GOCACHE="${PWD}/.cache/go-build" go build -o ./tools/sow-toolkit ./cmd/nwn-tool GOOS=windows GOARCH=amd64 GOCACHE="${PWD}/.cache/go-build" go build -o ./tools/sow-toolkit.exe ./cmd/nwn-tool go version -m ./tools/sow-toolkit - name: Pack release bundles id: pack env: TAG_NAME: ${{ github.ref_name }} run: | set -euo pipefail CHECKOUT_PATH="${CHECKOUT_PATH:-/home/ubuntu/tools-checkout}" cd "${CHECKOUT_PATH}" linux_binary="tools/sow-toolkit" windows_binary="tools/sow-toolkit.exe" if [[ ! -x "${linux_binary}" ]]; then echo "Missing built tool: ${linux_binary}" exit 1 fi if [[ ! -f "${windows_binary}" ]]; then echo "Missing built tool: ${windows_binary}" exit 1 fi linux_archive="/tmp/sow-toolkit-linux-amd64-${TAG_NAME}.tar.gz" windows_archive="/tmp/sow-toolkit-windows-amd64-${TAG_NAME}.exe" tar -czf "${linux_archive}" -C tools sow-toolkit cp "${windows_binary}" "${windows_archive}" echo "linux_archive=${linux_archive}" >> "$GITHUB_OUTPUT" echo "linux_asset_name=sow-toolkit-linux-amd64.tar.gz" >> "$GITHUB_OUTPUT" echo "windows_archive=${windows_archive}" >> "$GITHUB_OUTPUT" echo "windows_asset_name=sow-toolkit-windows-amd64.exe" >> "$GITHUB_OUTPUT" echo "tag=${TAG_NAME}" >> "$GITHUB_OUTPUT" - name: Create release and upload artifacts env: GITEA_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITEA_SERVER_URL: ${{ github.server_url }} GITEA_REPO: ${{ github.repository }} LINUX_ARCHIVE: ${{ steps.pack.outputs.linux_archive }} LINUX_ASSET_NAME: ${{ steps.pack.outputs.linux_asset_name }} WINDOWS_ARCHIVE: ${{ steps.pack.outputs.windows_archive }} WINDOWS_ASSET_NAME: ${{ steps.pack.outputs.windows_asset_name }} TAG_NAME: ${{ steps.pack.outputs.tag }} run: | set -euo pipefail API="${GITEA_SERVER_URL%/}/api/v1" OWNER="${GITEA_REPO%%/*}" NAME="${GITEA_REPO#*/}" AUTH=(-H "Authorization: token ${GITEA_API_TOKEN}" -H "Accept: application/json") RESP_FILE=/tmp/gitea-release.json CODE=$(curl -sS -o "${RESP_FILE}" -w "%{http_code}" "${AUTH[@]}" \ "${API}/repos/${OWNER}/${NAME}/releases/tags/${TAG_NAME}") if [[ "${CODE}" == "200" ]]; then RELEASE_ID=$(jq -r '.id' "${RESP_FILE}") else BODY=$(jq -n --arg t "${TAG_NAME}" \ '{tag_name: $t, name: $t, body: "sow-toolkit binary release built by Gitea Actions."}') CODE=$(curl -sS -o "${RESP_FILE}" -w "%{http_code}" "${AUTH[@]}" \ -X POST -H "Content-Type: application/json" \ -d "${BODY}" \ "${API}/repos/${OWNER}/${NAME}/releases") if [[ "${CODE}" != "201" && "${CODE}" != "200" ]]; then echo "Create release failed (HTTP ${CODE}):" cat "${RESP_FILE}" exit 1 fi RELEASE_ID=$(jq -r '.id' "${RESP_FILE}") fi for name in "${LINUX_ASSET_NAME}" "${WINDOWS_ASSET_NAME}"; do ASSET_ID=$(jq -r --arg name "${name}" '.assets[]? | select(.name == $name) | .id' "${RESP_FILE}" | head -n1) if [[ -n "${ASSET_ID}" ]]; then curl -sS -f "${AUTH[@]}" -X DELETE \ "${API}/repos/${OWNER}/${NAME}/releases/${RELEASE_ID}/assets/${ASSET_ID}" fi done curl -sS -f "${AUTH[@]}" -X POST \ -F "attachment=@${LINUX_ARCHIVE}" \ "${API}/repos/${OWNER}/${NAME}/releases/${RELEASE_ID}/assets?name=${LINUX_ASSET_NAME}" curl -sS -f "${AUTH[@]}" -X POST \ -F "attachment=@${WINDOWS_ARCHIVE}" \ "${API}/repos/${OWNER}/${NAME}/releases/${RELEASE_ID}/assets?name=${WINDOWS_ASSET_NAME}" - name: Cleanup temporary files if: always() env: TAG_NAME: ${{ github.ref_name }} run: | rm -f \ "/tmp/sow-toolkit-linux-amd64-${TAG_NAME}.tar.gz" \ "/tmp/sow-toolkit-windows-amd64-${TAG_NAME}.exe" \ /tmp/gitea-release.json - name: Prune old releases (keep latest 1) env: GITEA_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITEA_SERVER_URL: ${{ github.server_url }} GITEA_REPO: ${{ github.repository }} run: | set -euo pipefail API="${GITEA_SERVER_URL%/}/api/v1" OWNER="${GITEA_REPO%%/*}" NAME="${GITEA_REPO#*/}" AUTH=(-H "Authorization: token ${GITEA_API_TOKEN}" -H "Accept: application/json") curl -sS "${AUTH[@]}" \ "${API}/repos/${OWNER}/${NAME}/releases?limit=50&page=1" \ -o /tmp/all-releases.json jq -r '.[1:][].id' /tmp/all-releases.json | while read -r rid; do [[ -n "${rid}" ]] || continue curl -sS -f "${AUTH[@]}" -X DELETE \ "${API}/repos/${OWNER}/${NAME}/releases/${rid}" done rm -f /tmp/all-releases.json