2025-12-24 03:25:40 +00:00
# Advanced Release Pipeline with auto-upload to Gitea/Forgejo
# Triggers on tags: v*
when :
event : tag
tag : v*
steps :
# Create GitHub-style release via Gitea API
create-release :
image : alpine:latest
secrets : [ gitea_token]
commands :
- apk add --no-cache curl jq
- |
RELEASE_DATA=$(jq -n \
--arg tag "${CI_COMMIT_TAG}" \
--arg name "Release ${CI_COMMIT_TAG}" \
--arg body "Automated release from Woodpecker CI" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}' )
2025-12-25 22:59:45 +00:00
2025-12-24 03:25:40 +00:00
RELEASE_ID=$(curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "${RELEASE_DATA}" | jq -r '.id')
2025-12-25 22:59:45 +00:00
2025-12-24 03:25:40 +00:00
echo "RELEASE_ID=${RELEASE_ID}" >> /tmp/release.env
echo "✓ Created release ${CI_COMMIT_TAG} (ID: ${RELEASE_ID})"
# Build binaries for all platforms (matrix)
build-binaries :
image : rust:latest
matrix :
TARGET :
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-pc-windows-msvc
commands :
- |
if [[ "${TARGET}" == *"aarch64"* || "${TARGET}" == *"windows"* ]]; then
cargo install cross --git https://github.com/cross-rs/cross
cross build --release --target ${TARGET} --locked
else
rustup target add ${TARGET}
cargo build --release --target ${TARGET} --locked
fi
- mkdir -p dist
- |
if [[ "${TARGET}" == *"windows"* ]]; then
cp target/${TARGET}/release/*.exe dist/ || true
else
cp target/${TARGET}/release/typedialog* dist/ || true
rm -f dist/*.d dist/*.rlib || true
fi
- tar czf typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz -C dist .
- sha256sum typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz > typedialog-${CI_COMMIT_TAG}-${TARGET}.tar.gz.sha256
depends_on :
- create-release
# Generate SBOMs
generate-sbom :
image : rust:latest
commands :
- cargo install cargo-sbom --locked
- cargo sbom --output-format spdx_json_2_3 > sbom-spdx.json
- cargo sbom --output-format cyclone_dx_json_1_4 > sbom-cyclonedx.json
depends_on :
- create-release
# Upload all artifacts to Gitea release
upload-artifacts :
image : alpine:latest
secrets : [ gitea_token]
commands :
- apk add --no-cache curl jq
- source /tmp/release.env
- |
for file in typedialog-${CI_COMMIT_TAG}-*.tar.gz*; do
echo "Uploading ${file}..."
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/octet-stream" \
--data-binary "@${file}"
done
- |
for file in sbom-*.json; do
echo "Uploading ${file}..."
curl -X POST "${GITEA_URL}/api/v1/repos/${CI_REPO}/releases/${RELEASE_ID}/assets?name=${file}" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
--data-binary "@${file}"
done
- echo "✓ All artifacts uploaded successfully"
depends_on :
- build-binaries
- generate-sbom
# Optional: Publish to crates.io
publish-crates :
image : rust:latest
secrets : [ cargo_token]
when :
# Only if CARGO_TOKEN secret is set
evaluate : 'CI_PIPELINE_EVENT == "tag" && CI_COMMIT_TAG =~ "^v[0-9]"'
commands :
- |
for crate in typedialog-core typedialog-ag-core typedialog-ai typedialog-prov-gen typedialog typedialog-tui typedialog-web typedialog-ag typedialog-ag-server; do
echo "Publishing ${crate}..."
cargo publish -p ${crate} --token ${CARGO_TOKEN} || true
sleep 30
done
depends_on :
- upload-artifacts