# 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}') 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') 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