feat: add Azure Responses API and observable streaming #21
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*.*.*" | |
| permissions: | |
| contents: write | |
| packages: write | |
| env: | |
| GO_VERSION: "1.25.12" | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| # ──────────────────────────────────────────────────────────── | |
| # Test gate | |
| # ──────────────────────────────────────────────────────────── | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Vet | |
| run: go vet ./... | |
| - name: Test | |
| # -short runs the fast variants of the engine/queue load/soak tests | |
| # (the only tests gated on testing.Short()); the full 2000-run soak is a | |
| # timing-sensitive load test, not a gate — run it manually/nightly. | |
| run: go test -race -count=1 -timeout 120s -short ./... | |
| # ──────────────────────────────────────────────────────────── | |
| # Publish Go module | |
| # ──────────────────────────────────────────────────────────── | |
| publish-module: | |
| name: Publish Go Module | |
| runs-on: ubuntu-latest | |
| needs: test | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Request proxy to fetch new version | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/} | |
| echo "Publishing module version: $VERSION" | |
| GOPROXY=https://proxy.golang.org GO111MODULE=on \ | |
| go list -m github.com/spawn08/chronos@${VERSION} || true | |
| # ──────────────────────────────────────────────────────────── | |
| # Build cross-platform binaries | |
| # Targets: Linux (amd64/arm64), macOS Intel (amd64), | |
| # macOS Apple Silicon (arm64), Windows (amd64/arm64) | |
| # ──────────────────────────────────────────────────────────── | |
| build-binaries: | |
| name: Build ${{ matrix.target }} | |
| runs-on: ${{ matrix.runner }} | |
| needs: test | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux amd64 (Ubuntu, Debian, RHEL, CentOS, Fedora, Alpine) | |
| - target: linux-amd64 | |
| runner: ubuntu-latest | |
| goos: linux | |
| goarch: amd64 | |
| # Linux arm64 (Ubuntu arm64, AWS Graviton, Raspberry Pi 64-bit) | |
| - target: linux-arm64 | |
| runner: ubuntu-latest | |
| goos: linux | |
| goarch: arm64 | |
| # macOS Intel (x86_64) | |
| - target: darwin-amd64 | |
| runner: macos-latest | |
| goos: darwin | |
| goarch: amd64 | |
| # macOS Apple Silicon (M1/M2/M3/M4) | |
| - target: darwin-arm64 | |
| runner: macos-latest | |
| goos: darwin | |
| goarch: arm64 | |
| # Windows amd64 | |
| - target: windows-amd64 | |
| runner: windows-latest | |
| goos: windows | |
| goarch: amd64 | |
| # Windows arm64 | |
| - target: windows-arm64 | |
| runner: windows-latest | |
| goos: windows | |
| goarch: arm64 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Determine version metadata | |
| id: meta | |
| shell: bash | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/} | |
| COMMIT=$(git rev-parse --short HEAD) | |
| BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "commit=$COMMIT" >> "$GITHUB_OUTPUT" | |
| echo "build_date=$BUILD_DATE" >> "$GITHUB_OUTPUT" | |
| - name: Build binary | |
| shell: bash | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: "0" | |
| run: | | |
| BINARY_NAME="chronos-${{ matrix.goos }}-${{ matrix.goarch }}" | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| BINARY_NAME="${BINARY_NAME}.exe" | |
| fi | |
| go build -trimpath -ldflags "-s -w \ | |
| -X github.com/spawn08/chronos/cli/cmd.Version=${{ steps.meta.outputs.version }} \ | |
| -X github.com/spawn08/chronos/cli/cmd.Commit=${{ steps.meta.outputs.commit }} \ | |
| -X github.com/spawn08/chronos/cli/cmd.BuildDate=${{ steps.meta.outputs.build_date }}" \ | |
| -o "${BINARY_NAME}" ./cli/main.go | |
| echo "Built: ${BINARY_NAME}" | |
| ls -lh "${BINARY_NAME}" | |
| - name: Create tarball (Linux/macOS) | |
| if: matrix.goos != 'windows' | |
| shell: bash | |
| run: | | |
| BINARY_NAME="chronos-${{ matrix.goos }}-${{ matrix.goarch }}" | |
| ARCHIVE_NAME="chronos-${{ steps.meta.outputs.version }}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz" | |
| FILES="${BINARY_NAME}" | |
| [ -f LICENSE ] && FILES="${FILES} LICENSE" | |
| [ -f README.md ] && FILES="${FILES} README.md" | |
| tar czf "${ARCHIVE_NAME}" ${FILES} | |
| echo "Archive: ${ARCHIVE_NAME}" | |
| ls -lh "${ARCHIVE_NAME}" | |
| - name: Create zip (Windows) | |
| if: matrix.goos == 'windows' | |
| shell: pwsh | |
| run: | | |
| $version = "${{ steps.meta.outputs.version }}" | |
| $archiveName = "chronos-${version}-${{ matrix.goos }}-${{ matrix.goarch }}.zip" | |
| $files = @("chronos-${{ matrix.goos }}-${{ matrix.goarch }}.exe") | |
| if (Test-Path "LICENSE") { $files += "LICENSE" } | |
| if (Test-Path "README.md") { $files += "README.md" } | |
| Compress-Archive -Path $files -DestinationPath $archiveName | |
| Write-Host "Archive: $archiveName" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: chronos-${{ matrix.target }} | |
| path: | | |
| chronos-*.tar.gz | |
| chronos-*.zip | |
| chronos-${{ matrix.goos }}-${{ matrix.goarch }}* | |
| retention-days: 1 | |
| # ──────────────────────────────────────────────────────────── | |
| # GitHub Release with all artifacts | |
| # ──────────────────────────────────────────────────────────── | |
| github-release: | |
| name: GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: build-binaries | |
| if: always() && !contains(needs.build-binaries.result, 'failure') | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| merge-multiple: true | |
| - name: List artifacts | |
| run: | | |
| echo "=== Downloaded artifacts ===" | |
| ls -lhR artifacts/ 2>/dev/null || echo "No artifacts directory" | |
| - name: Generate source SBOM (SPDX) | |
| uses: anchore/sbom-action@v0 | |
| with: | |
| path: . | |
| format: spdx-json | |
| output-file: artifacts/chronos-${{ github.ref_name }}-sbom.spdx.json | |
| - name: Generate checksums | |
| run: | | |
| cd artifacts | |
| sha256sum chronos-*.tar.gz chronos-*.zip chronos-linux-* chronos-darwin-* chronos-windows-* chronos-*-sbom.spdx.json 2>/dev/null | sort > checksums-sha256.txt || true | |
| if [ ! -s checksums-sha256.txt ]; then | |
| echo "WARNING: No files matched for checksums" | |
| exit 1 | |
| fi | |
| echo "=== SHA-256 Checksums ===" | |
| cat checksums-sha256.txt | |
| - name: Determine version | |
| id: version | |
| run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| name: Chronos ${{ steps.version.outputs.tag }} | |
| generate_release_notes: true | |
| body: | | |
| ## Installation | |
| ### Quick Install (Linux / macOS) | |
| ```bash | |
| curl -fsSL https://raw.githubusercontent.com/${{ github.repository }}/main/install.sh | bash | |
| ``` | |
| Or install a specific version: | |
| ```bash | |
| curl -fsSL https://raw.githubusercontent.com/${{ github.repository }}/main/install.sh | bash -s -- ${{ steps.version.outputs.tag }} | |
| ``` | |
| ### Manual Download | |
| | Platform | Architecture | Download | | |
| |----------|-------------|----------| | |
| | **Linux** | x86_64 (amd64) | [chronos-${{ steps.version.outputs.tag }}-linux-amd64.tar.gz](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-linux-amd64.tar.gz) | | |
| | **Linux** | ARM64 | [chronos-${{ steps.version.outputs.tag }}-linux-arm64.tar.gz](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-linux-arm64.tar.gz) | | |
| | **macOS** | Intel (x86_64) | [chronos-${{ steps.version.outputs.tag }}-darwin-amd64.tar.gz](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-darwin-amd64.tar.gz) | | |
| | **macOS** | Apple Silicon (M1+) | [chronos-${{ steps.version.outputs.tag }}-darwin-arm64.tar.gz](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-darwin-arm64.tar.gz) | | |
| | **Windows** | x86_64 (amd64) | [chronos-${{ steps.version.outputs.tag }}-windows-amd64.zip](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-windows-amd64.zip) | | |
| | **Windows** | ARM64 | [chronos-${{ steps.version.outputs.tag }}-windows-arm64.zip](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/chronos-${{ steps.version.outputs.tag }}-windows-arm64.zip) | | |
| ### Verify Checksum | |
| ```bash | |
| sha256sum -c checksums-sha256.txt | |
| ``` | |
| files: | | |
| artifacts/chronos-*.tar.gz | |
| artifacts/chronos-*.zip | |
| artifacts/chronos-linux-* | |
| artifacts/chronos-darwin-* | |
| artifacts/chronos-windows-* | |
| artifacts/chronos-*-sbom.spdx.json | |
| artifacts/checksums-sha256.txt | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ──────────────────────────────────────────────────────────── | |
| # Docker image → GitHub Container Registry | |
| # ──────────────────────────────────────────────────────────── | |
| docker: | |
| name: Docker Image | |
| runs-on: ubuntu-latest | |
| needs: test | |
| permissions: | |
| contents: read | |
| packages: write | |
| # id-token for keyless (OIDC) cosign signing; security-events for | |
| # uploading the Trivy image-scan SARIF to the Security tab. | |
| id-token: write | |
| security-events: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern={{major}} | |
| type=sha | |
| - name: Build and push Docker image | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: deploy/docker/Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT=${{ github.sha }} | |
| # ── Supply-chain hardening for the published image ───────── | |
| - name: Scan image with Trivy | |
| # Pinned release tags for this action have been unreliable to resolve; | |
| # track master (maintained by aquasecurity). | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| format: sarif | |
| output: trivy-image.sarif | |
| severity: CRITICAL,HIGH | |
| ignore-unfixed: true | |
| - name: Upload Trivy image SARIF | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: trivy-image.sarif | |
| category: trivy-image | |
| - name: Generate image SBOM (SPDX) | |
| uses: anchore/sbom-action@v0 | |
| with: | |
| image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| format: spdx-json | |
| output-file: image-sbom.spdx.json | |
| # The image SBOM is attested to the image via cosign below; don't also | |
| # upload it as a release asset (this job is least-privilege | |
| # contents: read, and the source SBOM is already on the release). | |
| upload-release-assets: false | |
| - name: Sign the published image (keyless OIDC) | |
| env: | |
| IMAGE_REF: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| run: cosign sign --yes "${IMAGE_REF}" | |
| - name: Attest image SBOM (keyless OIDC) | |
| env: | |
| IMAGE_REF: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} | |
| run: | | |
| cosign attest --yes \ | |
| --predicate image-sbom.spdx.json \ | |
| --type spdxjson \ | |
| "${IMAGE_REF}" |