CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | name: Release self-host binaries
# Build the single-binary Gluecron distribution for all four target
# platforms on every `v*.*.*` tag, upload to the GitHub Release, and
# mirror the artifacts to the running Gluecron host so the
# `curl gluecron.com/install-server | bash` flow picks them up
# immediately.
permissions:
contents: write
on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
targets:
description: "Comma-separated targets (default: all four)"
required: false
default: "linux-x64,linux-arm64,darwin-x64,darwin-arm64"
concurrency:
group: release-binaries-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
name: build-${{ matrix.target }}
strategy:
fail-fast: false
matrix:
include:
- target: linux-x64
runs-on: ubuntu-latest
- target: linux-arm64
runs-on: ubuntu-latest
- target: darwin-x64
runs-on: macos-latest
- target: darwin-arm64
runs-on: macos-latest
runs-on: ${{ matrix.runs-on }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install deps
run: bun install --frozen-lockfile
- name: Build target
env:
GLUECRON_BUILD_TARGETS: ${{ matrix.target }}
run: bash scripts/build-self-host-binary.sh
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: gluecron-server-${{ matrix.target }}
path: |
dist/gluecron-server-${{ matrix.target }}
dist/gluecron-server-${{ matrix.target }}.sha256
if-no-files-found: error
retention-days: 7
publish:
name: publish
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Download all binary artifacts
uses: actions/download-artifact@v4
with:
pattern: gluecron-server-*
merge-multiple: true
path: dist
- name: Build ancillary bundles (hook + migrations + env.example)
# Re-run the bundle step with no targets so it only rebuilds the
# ancillary assets + the combined manifest. Existing binaries in
# dist/ are left in place.
env:
GLUECRON_BUILD_TARGETS: "linux-x64"
run: |
# Make sure the script can find every binary the matrix produced.
ls -la dist/
# Compute combined SHA256SUMS across whatever binaries landed.
(
cd dist
: > SHA256SUMS
for f in gluecron-server-*; do
if [ -f "$f" ] && [[ "$f" != *.sha256 ]]; then
sha256sum "$f" >> SHA256SUMS
fi
done
)
# Bundle the post-receive hook + migrations + env.example.
cp -f src/hooks/post-receive.ts dist/post-receive || true
tar -czf dist/migrations.tar.gz drizzle || true
cp -f .env.example dist/env.example || true
(
cd dist
for f in post-receive migrations.tar.gz env.example; do
if [ -f "$f" ]; then
sha256sum "$f" >> SHA256SUMS
fi
done
)
node -p "require('./package.json').version" > dist/VERSION
ls -la dist/
- name: Publish GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: false
files: |
dist/gluecron-server-linux-x64
dist/gluecron-server-linux-arm64
dist/gluecron-server-darwin-x64
dist/gluecron-server-darwin-arm64
dist/SHA256SUMS
dist/VERSION
dist/post-receive
dist/migrations.tar.gz
dist/env.example
- name: Mirror to Gluecron release endpoint
# Best-effort: POST each artifact to the running Gluecron site so
# /dist/<filename> serves the new bundle without a deploy. Requires
# GLUECRON_RELEASE_TOKEN (admin scope) + GLUECRON_RELEASE_URL secrets.
if: ${{ env.GLUECRON_RELEASE_URL != '' }}
env:
GLUECRON_RELEASE_URL: ${{ secrets.GLUECRON_RELEASE_URL }}
GLUECRON_RELEASE_TOKEN: ${{ secrets.GLUECRON_RELEASE_TOKEN }}
run: |
set -e
for f in dist/gluecron-server-* dist/SHA256SUMS dist/VERSION \
dist/post-receive dist/migrations.tar.gz dist/env.example; do
[ -f "$f" ] || continue
name=$(basename "$f")
echo "Uploading $name → $GLUECRON_RELEASE_URL"
curl -fsSL --max-time 120 \
-H "Authorization: Bearer $GLUECRON_RELEASE_TOKEN" \
-H "X-Filename: $name" \
--data-binary "@$f" \
"$GLUECRON_RELEASE_URL" || echo "mirror failed for $name (non-fatal)"
done
|