-
Notifications
You must be signed in to change notification settings - Fork 17
153 lines (151 loc) · 5.86 KB
/
Copy pathrelease.daily.yml
File metadata and controls
153 lines (151 loc) · 5.86 KB
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
name: daily
on:
workflow_call:
inputs:
component:
required: true
type: string
playbook:
required: true
type: string
infra_branch:
required: false
type: string
default: ''
jobs:
release:
name: Build ${{ inputs.component }}
runs-on: ubuntu-24.04-16c-64gb
outputs:
deb_version: ${{ steps.deb.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- uses: Swatinem/rust-cache@v2
# proxy.golang.org occasionally drops a module zip mid-transfer (HTTP/2
# INTERNAL_ERROR). The go command does not retry, so the failure surfaces
# as a GoReleaser build error partway through the release. Populate the
# module cache up front, where a retry is cheap and side-effect free.
#
# Best-effort only: this must never be a new way for the release to fail.
# It downloads every module go.mod requires, a superset of what the built
# binaries import, so a durable proxy failure on a test-only dependency
# would otherwise block a release that used to succeed. GoReleaser fetches
# whatever is still missing. The bound covers a stalled (as opposed to
# dropped) transfer, which would otherwise hang to the six-hour job
# default and suppress the daily-failure Slack alert that needs this job.
- name: Download Go modules
continue-on-error: true
timeout-minutes: 10
run: |
for attempt in 1 2 3; do
echo "go mod download (attempt $attempt/3)"
if go mod download; then
exit 0
fi
sleep $((attempt * 10))
done
echo "go mod download failed after 3 attempts"
exit 1
- name: Set env vars
run: ./scripts/env.sh >> $GITHUB_ENV
- name: Install rust for cli
uses: dtolnay/rust-toolchain@1.97.1
with:
targets: x86_64-unknown-linux-musl
- name: Install dependencies for rpm packaging
run: |
sudo apt update
sudo apt-get install squashfs-tools rpm gcc-x86-64-linux-gnu musl-tools -y
- name: Set build date
run: echo "BUILD_DATE=$(date -u +%Y%m%d%H%M%S)" >> $GITHUB_ENV
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser-pro
args: release -f release/.goreleaser.devnet.${{ inputs.component }}.yaml --clean --nightly
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
CLOUDSMITH_TOKEN: ${{ secrets.CLOUDSMITH_TOKEN }}
- name: Read the deb version GoReleaser built
id: deb
run: |
version=""
deb=$(jq -r '[.[] | select(.type == "Linux Package" and (.name | endswith(".deb")))][0].name // empty' dist/artifacts.json)
if [ -n "$deb" ]; then
version=$(jq -r '.version' dist/metadata.json)
case "$deb" in
*"$version"*) ;;
*) echo "::error::$deb does not carry the version $version that CloudSmith will index"; exit 1 ;;
esac
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
deploy:
name: Deploy ${{ inputs.component }} to DevNet
runs-on: self-hosted
needs: release
steps:
- name: Wait for CloudSmith to list the new package
if: needs.release.outputs.deb_version != ''
env:
VERSION: ${{ needs.release.outputs.deb_version }}
run: |
deadline=$((SECONDS + 600))
attempt=0
while [ "$SECONDS" -lt "$deadline" ]; do
attempt=$((attempt + 1))
missing=""
for suite in jammy noble; do
url="https://dl.cloudsmith.io/public/malbeclabs/doublezero-devnet/deb/ubuntu/dists/$suite/main/binary-amd64/Packages"
status=0
index=$(curl -sfL --max-time 30 "$url") || status=$?
if [ "$status" -ne 0 ]; then
echo "attempt $attempt: $suite index fetch failed, curl exit $status"
missing="$missing $suite"
elif ! grep -qF "Version: $VERSION" <<<"$index"; then
missing="$missing $suite"
fi
done
if [ -z "$missing" ]; then
echo "CloudSmith lists $VERSION on attempt $attempt"
# CloudFront serves the index with max-age=30, and each host reaches a
# different edge than this runner. Outlast an edge that cached the index
# just before CloudSmith rebuilt it.
sleep 35
exit 0
fi
echo "attempt $attempt: $VERSION is missing from$missing"
sleep 15
done
echo "::error::CloudSmith did not list $VERSION after $attempt attempts over ${SECONDS}s"
exit 1
- uses: actions/checkout@v4
- name: Checkout infra repo with ansible playbooks
uses: actions/checkout@v4
with:
repository: "malbeclabs/infra"
ref: ${{ inputs.infra_branch || '' }}
path: infra
token: ${{ secrets.GA_ANSIBLE_REPO_RO }}
- name: Create ansible vault password file
working-directory: infra/ansible
run: |
cat <<'EOT' > .vault_pass
#!/usr/bin/bash
echo "${ANSIBLE_VAULT_PASS}"
EOT
chmod +x .vault_pass
- name: Run ansible playbook
working-directory: infra/ansible
shell: bash -leo pipefail {0}
run: ansible-playbook -D --private-key ~/.ssh/id_runner --vault-password-file .vault_pass -i inventory/devnet/hosts.yml ${{ inputs.playbook }}
env:
ANSIBLE_VAULT_PASS: ${{ secrets.ANSIBLE_VAULT_PASS }}