Skip to content

feat(upload): store upload and GoReleaser self-distribution - #13

Merged
davidcreated merged 1 commit into
developfrom
feat/upload
Jul 23, 2026
Merged

feat(upload): store upload and GoReleaser self-distribution#13
davidcreated merged 1 commit into
developfrom
feat/upload

Conversation

@davidcreated

Copy link
Copy Markdown
Contributor

What

Milestone 4: the final pipeline step, plus making anvil installable.

  • internal/upload with an Uploader interface and three targets:
    • iOS: xcrun altool --upload-app to App Store Connect / TestFlight (macOS).
    • Android: the Google Play Publisher API via the official Go client (insert edit, upload bundle, assign track, commit) with a service-account JWT.
    • npm: npm publish.
  • Credentials from flag, env, or a *_BASE64 env decoded to a 0600 temp file; a credential inside the repo is refused. anvil upload is a dry run unless --yes.
  • GoReleaser self-distribution: .goreleaser.yaml + a tag-triggered release.yml that build cross-platform binaries and publish a GitHub release plus Homebrew cask and Scoop manifests.

Verification

  • ./check and staticcheck green. anvil upload --dry-run verified for iOS, Android, and npm.
  • Live store uploads and a live GoReleaser publish are deferred (need real accounts, an ASC key, a Play service account, and the tap PAT).

User setup before first release / upload

  • Create openforge-oss/homebrew-tap and openforge-oss/scoop-bucket repos and a HOMEBREW_TAP_TOKEN secret.
  • Provide store credentials at upload time via env or files.

Deferred (issues)

App Store submission metadata, Play staged rollout and track promotion, fastlane back-ends, anvil build --upload phase integration, npm Trusted Publishing (OIDC).

Add internal/upload with an Uploader interface and three targets: iOS via xcrun altool (App Store Connect/TestFlight), Android via the Google Play Publisher API (insert edit, upload bundle, assign track, commit) using a service-account JWT, and npm via npm publish. Credentials resolve from flag, env, or a base64 env decoded to a 0600 temp file, and are refused if they live inside the repo. anvil upload is a dry run unless --yes. Add GoReleaser (.goreleaser.yaml) and a tag-triggered release workflow that build cross-platform binaries and publish a GitHub release plus Homebrew cask and Scoop manifests. Tests cover credential resolution, the in-repo refusal, and each uploader's Validate/Describe.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 63eabcdc-f7ac-44bf-a4fb-77fbf4f36306

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/upload

Comment @coderabbitai help to get the list of available commands.

@davidcreated
davidcreated merged commit c17f5c1 into develop Jul 23, 2026
6 checks passed
davidcreated added a commit that referenced this pull request Jul 23, 2026
* feat(detect): stack detection engine and anvil detect command

Add internal/detect with marker-file detectors for Flutter (vs pure Dart; app/module/plugin), React Native (bare, Expo managed, Expo prebuild), native Android (app vs library, KMP flag), and native iOS (Xcode/SPM/Podfile). A depth-limited prune-on-detect scanner with skip lists and a containment sweep attributes android/ios folders to their Flutter or RN parent and surfaces each monorepo project once. Add the Cobra-based anvil detect command (table and --json, with --path and --depth). 16 fixture-tree tests cover the edge cases (node_modules exclusion, monorepo, KMP, plugin example pruning). Also apply the no-emojis, no-dash-connectors, minimal-comments style across docs and record it in CLAUDE.md.

* feat(build): guided build lifecycle and anvil build (#3)

* feat(build): guided build lifecycle and anvil build

Add the driver contract (internal/driver) and drivers for Flutter, React Native, native Android, native iOS, Swift (SPM), and Kotlin/JVM, with --flavor threaded into build and test steps. Add the runner (internal/pipeline) that streams combined output, captures exit codes, classifies results, collects artifacts, and fail-fasts. Add internal/tui with a Bubble Tea view and a plain non-TTY renderer, and the anvil build command (--path/--target/--flavor/--release/--dry-run/--plain). Refine detection so Gradle is not always Android and Package.swift is Swift, adding Swift and Kotlin stacks. Tests cover driver steps, the runner via a real subprocess, and the plain renderer.

* fix: remove unused dirExists helper (staticcheck U1000)

* feat(sign): guided release signing (#11)

Add a Sign phase and the anvil sign command plus anvil build --sign. internal/sign generates a PKCS12 keystore with keytool, writes key.properties, wires Gradle signingConfigs, writes an iOS ExportOptions.plist, and gitignores the secrets. iOS sign steps live on the Flutter (flutter build ipa), React Native, and native iOS (xcodebuild archive + exportArchive) drivers; Android signs at build time via the wired Gradle config. Passwords come from prompts (huh) or environment, never the repo, and --dry-run makes no changes. Tests cover live keystore generation (keytool), Gradle wiring idempotence, gitignore, ExportOptions, and step argv.

* feat(upload): store upload and GoReleaser self-distribution (#13)

Add internal/upload with an Uploader interface and three targets: iOS via xcrun altool (App Store Connect/TestFlight), Android via the Google Play Publisher API (insert edit, upload bundle, assign track, commit) using a service-account JWT, and npm via npm publish. Credentials resolve from flag, env, or a base64 env decoded to a 0600 temp file, and are refused if they live inside the repo. anvil upload is a dry run unless --yes. Add GoReleaser (.goreleaser.yaml) and a tag-triggered release workflow that build cross-platform binaries and publish a GitHub release plus Homebrew cask and Scoop manifests. Tests cover credential resolution, the in-repo refusal, and each uploader's Validate/Describe.

* feat(detect,driver): Go and web/Node stacks (#14)

Add Go and web/Node as detectors and drivers, reusing the existing contract with no new dependencies. Go: go.mod detection (app vs library via a main-package scan); go mod download, go vet + gofmt -l (Analyze classified as failed on non-empty output), go test, go build. Web/Node: framework detection (Next, Nuxt, SvelteKit, Angular, Vite, CRA, Vue, Svelte, Astro, Remix, Gatsby); deps by lockfile (with Yarn Berry --immutable), lint, test (jest/vitest/script with CI=true), build via the package.json script. Monorepo roots (workspaces, pnpm-workspace.yaml, lerna, nx) are descended into rather than claimed, and a single-package Turbo repo is a leaf. Detector order appends Go then Web (Web last, most permissive).
davidcreated added a commit that referenced this pull request Jul 24, 2026
* feat(detect): stack detection engine and anvil detect command

Add internal/detect with marker-file detectors for Flutter (vs pure Dart; app/module/plugin), React Native (bare, Expo managed, Expo prebuild), native Android (app vs library, KMP flag), and native iOS (Xcode/SPM/Podfile). A depth-limited prune-on-detect scanner with skip lists and a containment sweep attributes android/ios folders to their Flutter or RN parent and surfaces each monorepo project once. Add the Cobra-based anvil detect command (table and --json, with --path and --depth). 16 fixture-tree tests cover the edge cases (node_modules exclusion, monorepo, KMP, plugin example pruning). Also apply the no-emojis, no-dash-connectors, minimal-comments style across docs and record it in CLAUDE.md.

* feat(build): guided build lifecycle and anvil build (#3)

* feat(build): guided build lifecycle and anvil build

Add the driver contract (internal/driver) and drivers for Flutter, React Native, native Android, native iOS, Swift (SPM), and Kotlin/JVM, with --flavor threaded into build and test steps. Add the runner (internal/pipeline) that streams combined output, captures exit codes, classifies results, collects artifacts, and fail-fasts. Add internal/tui with a Bubble Tea view and a plain non-TTY renderer, and the anvil build command (--path/--target/--flavor/--release/--dry-run/--plain). Refine detection so Gradle is not always Android and Package.swift is Swift, adding Swift and Kotlin stacks. Tests cover driver steps, the runner via a real subprocess, and the plain renderer.

* fix: remove unused dirExists helper (staticcheck U1000)

* feat(sign): guided release signing (#11)

Add a Sign phase and the anvil sign command plus anvil build --sign. internal/sign generates a PKCS12 keystore with keytool, writes key.properties, wires Gradle signingConfigs, writes an iOS ExportOptions.plist, and gitignores the secrets. iOS sign steps live on the Flutter (flutter build ipa), React Native, and native iOS (xcodebuild archive + exportArchive) drivers; Android signs at build time via the wired Gradle config. Passwords come from prompts (huh) or environment, never the repo, and --dry-run makes no changes. Tests cover live keystore generation (keytool), Gradle wiring idempotence, gitignore, ExportOptions, and step argv.

* feat(upload): store upload and GoReleaser self-distribution (#13)

Add internal/upload with an Uploader interface and three targets: iOS via xcrun altool (App Store Connect/TestFlight), Android via the Google Play Publisher API (insert edit, upload bundle, assign track, commit) using a service-account JWT, and npm via npm publish. Credentials resolve from flag, env, or a base64 env decoded to a 0600 temp file, and are refused if they live inside the repo. anvil upload is a dry run unless --yes. Add GoReleaser (.goreleaser.yaml) and a tag-triggered release workflow that build cross-platform binaries and publish a GitHub release plus Homebrew cask and Scoop manifests. Tests cover credential resolution, the in-repo refusal, and each uploader's Validate/Describe.

* feat(detect,driver): Go and web/Node stacks (#14)

Add Go and web/Node as detectors and drivers, reusing the existing contract with no new dependencies. Go: go.mod detection (app vs library via a main-package scan); go mod download, go vet + gofmt -l (Analyze classified as failed on non-empty output), go test, go build. Web/Node: framework detection (Next, Nuxt, SvelteKit, Angular, Vite, CRA, Vue, Svelte, Astro, Remix, Gatsby); deps by lockfile (with Yarn Berry --immutable), lint, test (jest/vitest/script with CI=true), build via the package.json script. Monorepo roots (workspaces, pnpm-workspace.yaml, lerna, nx) are descended into rather than claimed, and a single-package Turbo repo is a leaf. Detector order appends Go then Web (Web last, most permissive).

* chore(release): prepare v0.1.0 (#16)

Rewrite the README for the released tool (eight stacks, full detect/build/sign/upload pipeline, install via binary or go install, usage and flags). Make Homebrew and Scoop upload skip gracefully when HOMEBREW_TAP_TOKEN is absent, so the release ships binaries and the GitHub release without a token and auto-enables tap publishing once the secret is set.
davidcreated added a commit that referenced this pull request Jul 24, 2026
* feat(detect): stack detection engine and anvil detect command

Add internal/detect with marker-file detectors for Flutter (vs pure Dart; app/module/plugin), React Native (bare, Expo managed, Expo prebuild), native Android (app vs library, KMP flag), and native iOS (Xcode/SPM/Podfile). A depth-limited prune-on-detect scanner with skip lists and a containment sweep attributes android/ios folders to their Flutter or RN parent and surfaces each monorepo project once. Add the Cobra-based anvil detect command (table and --json, with --path and --depth). 16 fixture-tree tests cover the edge cases (node_modules exclusion, monorepo, KMP, plugin example pruning). Also apply the no-emojis, no-dash-connectors, minimal-comments style across docs and record it in CLAUDE.md.

* feat(build): guided build lifecycle and anvil build (#3)

* feat(build): guided build lifecycle and anvil build

Add the driver contract (internal/driver) and drivers for Flutter, React Native, native Android, native iOS, Swift (SPM), and Kotlin/JVM, with --flavor threaded into build and test steps. Add the runner (internal/pipeline) that streams combined output, captures exit codes, classifies results, collects artifacts, and fail-fasts. Add internal/tui with a Bubble Tea view and a plain non-TTY renderer, and the anvil build command (--path/--target/--flavor/--release/--dry-run/--plain). Refine detection so Gradle is not always Android and Package.swift is Swift, adding Swift and Kotlin stacks. Tests cover driver steps, the runner via a real subprocess, and the plain renderer.

* fix: remove unused dirExists helper (staticcheck U1000)

* feat(sign): guided release signing (#11)

Add a Sign phase and the anvil sign command plus anvil build --sign. internal/sign generates a PKCS12 keystore with keytool, writes key.properties, wires Gradle signingConfigs, writes an iOS ExportOptions.plist, and gitignores the secrets. iOS sign steps live on the Flutter (flutter build ipa), React Native, and native iOS (xcodebuild archive + exportArchive) drivers; Android signs at build time via the wired Gradle config. Passwords come from prompts (huh) or environment, never the repo, and --dry-run makes no changes. Tests cover live keystore generation (keytool), Gradle wiring idempotence, gitignore, ExportOptions, and step argv.

* feat(upload): store upload and GoReleaser self-distribution (#13)

Add internal/upload with an Uploader interface and three targets: iOS via xcrun altool (App Store Connect/TestFlight), Android via the Google Play Publisher API (insert edit, upload bundle, assign track, commit) using a service-account JWT, and npm via npm publish. Credentials resolve from flag, env, or a base64 env decoded to a 0600 temp file, and are refused if they live inside the repo. anvil upload is a dry run unless --yes. Add GoReleaser (.goreleaser.yaml) and a tag-triggered release workflow that build cross-platform binaries and publish a GitHub release plus Homebrew cask and Scoop manifests. Tests cover credential resolution, the in-repo refusal, and each uploader's Validate/Describe.

* feat(detect,driver): Go and web/Node stacks (#14)

Add Go and web/Node as detectors and drivers, reusing the existing contract with no new dependencies. Go: go.mod detection (app vs library via a main-package scan); go mod download, go vet + gofmt -l (Analyze classified as failed on non-empty output), go test, go build. Web/Node: framework detection (Next, Nuxt, SvelteKit, Angular, Vite, CRA, Vue, Svelte, Astro, Remix, Gatsby); deps by lockfile (with Yarn Berry --immutable), lint, test (jest/vitest/script with CI=true), build via the package.json script. Monorepo roots (workspaces, pnpm-workspace.yaml, lerna, nx) are descended into rather than claimed, and a single-package Turbo repo is a leaf. Detector order appends Go then Web (Web last, most permissive).

* chore(release): prepare v0.1.0 (#16)

Rewrite the README for the released tool (eight stacks, full detect/build/sign/upload pipeline, install via binary or go install, usage and flags). Make Homebrew and Scoop upload skip gracefully when HOMEBREW_TAP_TOKEN is absent, so the release ships binaries and the GitHub release without a token and auto-enables tap publishing once the secret is set.

* docs: real install instructions, and bump actions off Node 20 (#18)

README now shows the working Homebrew cask and Scoop bucket commands published by the v0.1.0 release, and notes that go install lands in GOPATH/bin. Mark 0.1.0 as released in the changelog instead of leaving shipped work under Unreleased. Bump actions/checkout to v7 and actions/setup-go to v7 across CI and release, clearing the Node 20 deprecation warning on the release run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant