-
Notifications
You must be signed in to change notification settings - Fork 2
175 lines (156 loc) · 8.05 KB
/
Copy pathrelease.yml
File metadata and controls
175 lines (156 loc) · 8.05 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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
name: Release
# Promove a imagem JÁ TESTADA de um commit de main para as tags de distribuição.
# NÃO rebuilda: re-aponta as tags para o MESMO digest que passou pelo CI e pelo
# teste de fumaça, ou seja, exatamente os bits que foram verificados.
#
# 1. merge em main → Publicar imagem publica :<sha> e :latest
# 2. validado → git tag v1.2.3 && git push origin v1.2.3
# 3. este workflow → promove :<sha> para :v1.2.3 (+ :stable)
#
# Pré-release (tag com hífen, ex. v1.2.3-rc1) não move :stable.
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
# write, e não read, porque este workflow cria a página do Release. É a única
# elevação aqui: ele não empurra código nem move branch.
contents: write
packages: write
env:
IMAGEM: ghcr.io/${{ github.repository }}/api
jobs:
promover:
runs-on: ubuntu-latest
steps:
# Precisa do histórico e das tags para montar as notas a partir dos
# commits desde a versão anterior.
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# O publicar.yml empurra :<sha> antes de conferir, e daqui só se sabe que
# a imagem existe, não que aquele workflow passou. Conferir de novo aqui é
# o que impede promover uma imagem com lib diferente da do release.
- name: baixa as libs do release
run: make acbr-libs-baixar
- name: as libs da imagem são as do release
run: scripts/conferir-libs-imagem.sh "${IMAGEM}:${GITHUB_SHA}" acbr-libs
- name: promove :<sha> → :vX.Y.Z (+ :stable)
run: |
set -eu
VERSAO="${GITHUB_REF_NAME}"
ORIGEM="${IMAGEM}:${GITHUB_SHA}"
if ! docker buildx imagetools inspect "$ORIGEM" >/dev/null 2>&1; then
echo "::error::$ORIGEM não existe no registry. Faça a tag num commit de main já publicado."
exit 1
fi
TAGS="-t ${IMAGEM}:${VERSAO}"
case "$VERSAO" in
*-*) echo "Pré-release ($VERSAO): não move :stable nem a tag maior." ;;
*)
# A tag maior (:v1) é a que o compose do README usa: ela acompanha
# correção e recurso dentro da major, e para de andar na virada,
# que é onde há quebra. Sem ela o exemplo do README aponta para
# uma tag que não existe.
MAIOR="${VERSAO%%.*}"
TAGS="$TAGS -t ${IMAGEM}:stable -t ${IMAGEM}:${MAIOR}"
;;
esac
# imagetools create copia o manifesto (mesmo digest) para as tags novas.
docker buildx imagetools create $TAGS "$ORIGEM"
docker buildx imagetools inspect "${IMAGEM}:${VERSAO}"
echo "tags publicadas: $(echo "$TAGS" | tr ' ' '\n' | grep -v '^-t$' | tr '\n' ' ')"
# Conferir, não presumir: cada tag nova tem de estar no digest de origem.
digest() { docker buildx imagetools inspect "$1" --format '{{json .Manifest}}' | jq -r .digest; }
DIGEST="$(digest "$ORIGEM")"
for t in $(echo "$TAGS" | tr ' ' '\n' | grep -v '^-t$'); do
d="$(digest "$t")"
if [ "$d" != "$DIGEST" ]; then
echo "::error::$t está em $d, a origem $ORIGEM está em $DIGEST"
exit 1
fi
done
echo "DIGEST=$DIGEST" >> "$GITHUB_ENV"
# Promover a imagem sem criar a página deixa a aba de Releases atrás das
# tags, e quem abre o repositório vê como "Latest" o que estiver lá, que
# já foi um pacote de binários de biblioteca.
- name: "publica a página do Release"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -eu
VERSAO="${GITHUB_REF_NAME}"
ANTERIOR="$(git describe --tags --abbrev=0 --match 'v*' "${VERSAO}^" 2>/dev/null || true)"
# Os binários da ACBrLib são anexos de UM release por revisão do ACBr,
# não de todo release: 56 MB em cada versão, inclusive nas que só
# mexem em documentação, não se justifica. O preço disso é que a
# página da versão pode não ter anexo nenhum, e quem procura os .so
# não descobre onde estão. Estas duas linhas resolvem isso, lendo do
# Makefile da própria tag. Vazio em tag anterior a ACBR_LIBS_RELEASE,
# e aí a linha não sai.
LIBS_REL="$(sed -n 's/^ACBR_LIBS_RELEASE[[:space:]]*?*=[[:space:]]*//p' Makefile | head -1)"
ACBR_R="$(sed -n 's/^ACBR_REV[[:space:]]*?*=[[:space:]]*//p' Makefile | head -1)"
# Conferir antes de afirmar. A linha abaixo diz ao leitor onde estão os
# .so, e o ci.yml e o publicar.yml só descobririam um release vazio no
# próximo push, depois da página já publicada com a promessa errada.
if [ -n "$LIBS_REL" ] && [ "$LIBS_REL" != "$VERSAO" ]; then
FALTA=""
TEM="$(gh release view "$LIBS_REL" --repo "$GITHUB_REPOSITORY" \
--json assets --jq '.assets[].name' 2>/dev/null || true)"
for a in libacbrnfse64.so libacbrcte64.so libacbrmdfe64.so \
libacbrnfe64.so libacbrboleto64.so schemas.tar.gz \
SHA256SUMS revisao.txt; do
printf '%s\n' "$TEM" | grep -qxF "$a" || FALTA="$FALTA $a"
done
if [ -n "$FALTA" ]; then
echo "::error::ACBR_LIBS_RELEASE aponta para $LIBS_REL, que não tem:$FALTA"
echo "::error::Publique com 'make acbr-libs-publicar' ou corrija ACBR_LIBS_RELEASE."
exit 1
fi
echo "anexos da ACBrLib conferidos em $LIBS_REL"
fi
NFSE_SHA="$(awk '$2 ~ /libacbrnfse64\.so$/ {print $1}' acbr-libs/SHA256SUMS)"
{
printf 'Imagem: `%s:%s`' "$IMAGEM" "$VERSAO"
case "$VERSAO" in
*-*) printf ' (pré-release: não move `:stable` nem a tag maior)\n' ;;
*) printf ', que é o mesmo digest de `:%s` e `:stable`.\n' "${VERSAO%%.*}" ;;
esac
printf '\n'
# O digest não muda quando alguém move uma tag. É ele que se fixa no
# deploy: image: ...@sha256:...
printf 'Digest: `%s@%s`\n\n' "$IMAGEM" "$DIGEST"
printf 'Lib de NFS-e na imagem: `libacbrnfse64.so` sha256 `%s`, conferida contra o `SHA256SUMS` do release das libs.\n\n' "$NFSE_SHA"
if [ -n "$LIBS_REL" ]; then
if [ "$LIBS_REL" = "$VERSAO" ]; then
printf 'Binários da ACBrLib (revisão r%s): anexos deste release.\n\n' "$ACBR_R"
else
printf 'Binários da ACBrLib (revisão r%s): anexos do release [%s](../releases/tag/%s). ' "$ACBR_R" "$LIBS_REL" "$LIBS_REL"
printf 'O `make acbr-libs-baixar` os busca de lá.\n\n'
fi
fi
if [ -n "$ANTERIOR" ]; then
printf '## Mudanças desde %s\n\n' "$ANTERIOR"
git log --no-merges --pretty='- %s' "${ANTERIOR}..${VERSAO}"
else
printf '## Primeira versão\n\nHistórico completo em `git log`.\n'
fi
printf '\n\nComo subir, escopo e o que conferir antes de apontar para produção:\n'
printf '[README](../blob/%s/README.md) e [docs/LIMITACOES.md](../blob/%s/docs/LIMITACOES.md).\n' "$VERSAO" "$VERSAO"
} > /tmp/notas.md
PRE=""
case "$VERSAO" in *-*) PRE="--prerelease --latest=false" ;; esac
# Idempotente: reexecutar o workflow atualiza as notas em vez de falhar.
if gh release view "$VERSAO" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release edit "$VERSAO" --repo "$GITHUB_REPOSITORY" \
--notes-file /tmp/notas.md $PRE
else
gh release create "$VERSAO" --repo "$GITHUB_REPOSITORY" \
--title "$VERSAO" --notes-file /tmp/notas.md --verify-tag $PRE
fi
echo "página: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${VERSAO}"