Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ permissions:

jobs:
test:
name: test (${{ matrix.check }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ["1.27.0", "1.27.1"]
include:
- go-version: "1.27.0"
check: "1.27.0"
# Preserve the required status name while testing the patched compiler.
- go-version: "1.27.2"
check: "1.27.1"
env:
GOTOOLCHAIN: local
steps:
Expand Down Expand Up @@ -44,7 +50,7 @@ jobs:
args: --timeout=3m

macos-release:
runs-on: macos-15
runs-on: xcode-27
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
Expand All @@ -63,3 +69,17 @@ jobs:
run: |
goreleaser check
goreleaser build --snapshot --clean
- name: Smoke-test both macOS architectures
run: |
arch -x86_64 /usr/bin/true || sudo softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /usr/bin/true
for target in amd64 arm64; do
for binary in dist/ordercli_darwin_"${target}"*/ordercli; do
test -x "$binary"
if [ "$target" = amd64 ]; then
arch -x86_64 "$binary" --version
else
"$binary" --version
fi
done
done
7 changes: 6 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ name: release
on:
workflow_dispatch:
inputs:
dry_run:
description: Build, sign and verify without creating tags or releases
type: boolean
default: true
version:
description: SemVer to release (for example 0.2.1)
required: true
Expand Down Expand Up @@ -30,8 +34,9 @@ jobs:
contents: write
pull-requests: write
statuses: read
uses: openclaw/release-workflows/.github/workflows/release-go-cli.yml@f613cbfed2b043159c850c353e7facb8c89833b0 # v1.9.0
uses: openclaw/release-workflows/.github/workflows/release-go-cli.yml@fc49859568b3781af7663bee48c003fd987dc08b # v1.11.8
with:
dry-run: ${{ inputs.dry_run }}
version: ${{ inputs.version }}
repository-type: personal
build-runner: macos
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Move macOS CI and release verification to Xcode 27, preserving macOS 13 and verifying Intel CLI execution under Rosetta; add non-publishing release dry runs.
- Build with patched Go 1.27.2 while retaining the Go 1.27.0 source minimum.

## 0.2.1 (2026-09-14)

**Highlights:** macOS downloads are signed and notarized.
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.27

ARG GO_VERSION=1.27.1
ARG GO_VERSION=1.27.2
ARG NPM_VERSION=12.0.2
ARG PLAYWRIGHT_VERSION=1.62.1

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Prebuilt archives for macOS, Linux, and Windows are available on the [GitHub rel

Requires Go 1.27 or newer.

The preferred build toolchain is Go 1.27.1; CI also verifies the Go 1.27.0 source minimum.
The preferred build toolchain is Go 1.27.2; CI also verifies the Go 1.27.0 source minimum. macOS release checks use the Apple Silicon `xcode-27` runner, preserve the macOS 13 minimum, and execute Intel binaries under Rosetta.

```sh
go test ./...
Expand Down
4 changes: 2 additions & 2 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ summary: 'Release checklist for ordercli (GitHub release + Homebrew tap)'

# Releasing ordercli

Dispatch `.github/workflows/release.yml` on the current protected `main` with a SemVer `version`. The caller pins the shared Go CLI archetype at v1.9.0 (`f613cbfed2b043159c850c353e7facb8c89833b0`). It freezes the source, creates the annotated `v<version>` tag, builds with GoReleaser, signs and notarizes macOS binaries, verifies on native arm64 and Intel runners, then publishes and updates `steipete/homebrew-tap`.
Dispatch `.github/workflows/release.yml` on the current protected `main` with a SemVer `version`. The caller pins the shared Go CLI archetype at v1.11.8 (`fc49859568b3781af7663bee48c003fd987dc08b`). It builds, signs, and verifies on `xcode-27`, using Rosetta for Intel execution. Dispatches default to `dry_run: true`, which does not create tags, publish releases, or update Homebrew. Explicit publication freezes the source, creates the annotated `v<version>` tag, then publishes verified artifacts and updates `steipete/homebrew-tap`.

The signing policy is `personal`: Developer ID Application: Peter Steinberger, team `Y5PE65HELJ`, identifier `com.steipete.ordercli.ordercli`. Native archives retain `ordercli_<version>_<os>_<arch>` names, tar.gz/Windows ZIP formats, and the README, license, and changelog. The release includes `checksums.txt`, `ASSET-INVENTORY.json`, `SIGNING-MANIFEST.json`, and `RELEASE-NOTES.md`; independent verifier attestations bind publication to the frozen source and exact signed bytes.

Expand All @@ -25,7 +25,7 @@ The release builds on macOS so the GoReleaser post-build hook can inspect each a
## Publish

- Confirm the version does not already exist as a local/remote tag or GitHub release.
- Dispatch `gh workflow run release.yml --ref main -f version=<version>`. The workflow owns annotated tag creation; do not create or push a tag manually.
- Dispatch `gh workflow run release.yml --ref main -f version=<version> -f dry_run=false`. The workflow owns annotated tag creation; do not create or push a tag manually. For verification only, use the current version with `-f dry_run=true`.
- Watch the release workflow, including its Homebrew handoff, to completion.
- The shared workflow publishes the finalized changelog section as both the release body and `RELEASE-NOTES.md`. Check it against `./scripts/release-notes v<version>`; preserve those exact notes after publication.

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/steipete/ordercli

go 1.27.0

toolchain go1.27.1
toolchain go1.27.2

require (
github.com/spf13/cobra v1.10.2
Expand Down
3 changes: 2 additions & 1 deletion internal/cli/glovo_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func TestGlovoCLI_ConfigSetAndShow(t *testing.T) {
cfgPath := filepath.Join(t.TempDir(), "config.json")

// Test config set
out, _, err := runCLI(cfgPath, []string{"glovo", "config", "set",
out, _, err := runCLI(cfgPath, []string{
"glovo", "config", "set",
"--city-code", "MAD",
"--country-code", "ES",
"--language", "en",
Expand Down
6 changes: 4 additions & 2 deletions internal/deliveroo/public_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"github.com/steipete/ordercli/internal/browserpage"
)

var quantityOnlyRe = regexp.MustCompile(`^\d+\s*x$`)
var readBrowserPageText = browserpage.ReadText
var (
quantityOnlyRe = regexp.MustCompile(`^\d+\s*x$`)
readBrowserPageText = browserpage.ReadText
)

type PublicStatus struct {
URL string `json:"url,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion internal/deliveroo/public_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func TestFetchPublicStatus(t *testing.T) {
return browserpage.Result{
FinalURL: "https://deliveroo.example/final",
Title: "Deliveroo",
Text: "This order is for Gildas\nDelivery\n221 Pentonville Road, FORA, N19UZ\nOrder Details\nTa'Mini\nOrder #5040",
Text: "This order is for Gildas\nDelivery\n221 Pentonville Road, FORA, N19UZ\nOrder Details\nTa'Mini\nOrder #5040",
}, nil
}

Expand Down
94 changes: 47 additions & 47 deletions internal/glovo/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ type BasketsResponse []Basket

// Basket represents a shopping cart for a store
type Basket struct {
StoreID int `json:"storeId"`
StoreAddressID int `json:"storeAddressId"`
StoreName string `json:"storeName"`
StoreSlug string `json:"storeSlug"`
Products []BasketItem `json:"products"`
SubTotal float64 `json:"subTotal"`
DeliveryFee float64 `json:"deliveryFee"`
ServiceFee float64 `json:"serviceFee"`
SmallOrderFee float64 `json:"smallOrderFee"`
Total float64 `json:"total"`
Currency string `json:"currency"`
MinOrderValue float64 `json:"minOrderValue"`
IsMinOrderMet bool `json:"isMinOrderMet"`
StoreID int `json:"storeId"`
StoreAddressID int `json:"storeAddressId"`
StoreName string `json:"storeName"`
StoreSlug string `json:"storeSlug"`
Products []BasketItem `json:"products"`
SubTotal float64 `json:"subTotal"`
DeliveryFee float64 `json:"deliveryFee"`
ServiceFee float64 `json:"serviceFee"`
SmallOrderFee float64 `json:"smallOrderFee"`
Total float64 `json:"total"`
Currency string `json:"currency"`
MinOrderValue float64 `json:"minOrderValue"`
IsMinOrderMet bool `json:"isMinOrderMet"`
}

// BasketItem represents an item in the cart
Expand All @@ -97,40 +97,40 @@ type BasketItem struct {

// UserResponse represents the response from /v3/me
type UserResponse struct {
ID int `json:"id"`
Type string `json:"type"`
URN string `json:"urn"`
Name string `json:"name"`
Picture *string `json:"picture"`
Email string `json:"email"`
Description *string `json:"description"`
FacebookID *string `json:"facebookId"`
PreferredCityCode string `json:"preferredCityCode"`
PreferredLanguage string `json:"preferredLanguage"`
PreferredLanguageRegion string `json:"preferredLanguageRegion"`
Locale string `json:"locale"`
DeviceURN *string `json:"deviceUrn"`
AnalyticsID *string `json:"analyticsId"`
MediaCampaign *string `json:"mediaCampaign"`
MediaSource *string `json:"mediaSource"`
OS *string `json:"os"`
DeliveredOrdersCount int `json:"deliveredOrdersCount"`
PhoneNumber *PhoneNumber `json:"phoneNumber"`
CompanyDetail *string `json:"companyDetail"`
VirtualBalance *Balance `json:"virtualBalance"`
FreeOrders int `json:"freeOrders"`
PaymentMethod string `json:"paymentMethod"`
PaymentWay string `json:"paymentWay"`
CurrentCard *string `json:"currentCard"`
AccumulatedDebt float64 `json:"accumulatedDebt"`
Defaulter bool `json:"defaulter"`
Gender *string `json:"gender"`
AgeMin *int `json:"ageMin"`
AgeMax *int `json:"ageMax"`
Birthday *string `json:"birthday"`
PrivacySettings any `json:"privacySettings"`
Permissions []Permission `json:"permissions"`
DataPrivacyEnabled bool `json:"dataPrivacyEnabled"`
ID int `json:"id"`
Type string `json:"type"`
URN string `json:"urn"`
Name string `json:"name"`
Picture *string `json:"picture"`
Email string `json:"email"`
Description *string `json:"description"`
FacebookID *string `json:"facebookId"`
PreferredCityCode string `json:"preferredCityCode"`
PreferredLanguage string `json:"preferredLanguage"`
PreferredLanguageRegion string `json:"preferredLanguageRegion"`
Locale string `json:"locale"`
DeviceURN *string `json:"deviceUrn"`
AnalyticsID *string `json:"analyticsId"`
MediaCampaign *string `json:"mediaCampaign"`
MediaSource *string `json:"mediaSource"`
OS *string `json:"os"`
DeliveredOrdersCount int `json:"deliveredOrdersCount"`
PhoneNumber *PhoneNumber `json:"phoneNumber"`
CompanyDetail *string `json:"companyDetail"`
VirtualBalance *Balance `json:"virtualBalance"`
FreeOrders int `json:"freeOrders"`
PaymentMethod string `json:"paymentMethod"`
PaymentWay string `json:"paymentWay"`
CurrentCard *string `json:"currentCard"`
AccumulatedDebt float64 `json:"accumulatedDebt"`
Defaulter bool `json:"defaulter"`
Gender *string `json:"gender"`
AgeMin *int `json:"ageMin"`
AgeMax *int `json:"ageMax"`
Birthday *string `json:"birthday"`
PrivacySettings any `json:"privacySettings"`
Permissions []Permission `json:"permissions"`
DataPrivacyEnabled bool `json:"dataPrivacyEnabled"`
}

// PhoneNumber represents a phone number with country code
Expand Down
Loading