Skip to content

Release/0.1.0#5

Merged
BrkYld merged 7 commits into
mainfrom
release/0.1.0
Jul 8, 2026
Merged

Release/0.1.0#5
BrkYld merged 7 commits into
mainfrom
release/0.1.0

Conversation

@BrkYld

@BrkYld BrkYld commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added support for separate upload and publish actions, including upload-only, publish-only, or both in one workflow.
    • Updated setup guidance with clearer examples for iOS and Android binaries and self-hosted environments.
    • Improved progress updates during publish runs.
  • Bug Fixes

    • Prevents starting a new publish when one is already in progress for the same profile.
    • Adds better validation for platform and app file type inputs.
    • Fails more clearly when publishing cannot complete successfully.

@BrkYld BrkYld requested a review from envergokmen July 8, 2026 12:21
@BrkYld BrkYld self-assigned this Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR splits the GitHub action into independent upload and publish switches. It adds publish-flow API functions for app-version lookup, release-candidate marking, active-publish queue counting, and status polling, wires them into main.ts, updates action.yml inputs, and rewrites README documentation. RELEASE_NOTE.md content was removed.

Changes

Upload/Publish switch and publish orchestration

Layer / File(s) Summary
Action input contract for upload/publish switches
action.yml
Adds upload and publish inputs (default 'false'), updates description text, and makes appPath optional.
Publish API helpers: versions, release candidates, queue, polling
src/api/publishApi.ts
Adds step-status utilities, app-version/release-candidate helpers, active-publish counting, switches upload basePath to v1, and adds getPublishId, startPublish, pollPublishStatus.
main.ts wiring for upload/publish inputs and guarded publish flow
src/main.ts
Parses upload/publish booleans, validates platform/appPath, guards against concurrent publishes, and branches upload/publish logic via shared appVersionId.
README and action metadata documentation updates
README.md, RELEASE_NOTE.md
Rewrites intro, adds "What the action does" and behavior matrix, updates usage examples, self-hosted example, reference link; removes old release notes content.

Poem

A rabbit hops through code so neat,
Two switches now, upload and complete!
Polling steps with emoji cheer,
Release candidates marked so clear.
No more clashing publish runs—
Just clean hops till the job is done! 🐇✨

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is a generic release label and does not describe the actual changes in the pull request. Use a concise title that names the main change, such as the new publish/upload workflow or README/action metadata updates.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/0.1.0
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch release/0.1.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@BrkYld BrkYld merged commit a11f8b1 into main Jul 8, 2026
1 of 2 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/main.ts (1)

130-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider replacing as string assertions with an explicit guard.

The control flow guarantees appVersionId is defined by this point (set on line 110 or line 124), but the as string assertions bypass TypeScript's type checking and would silently pass undefined downstream if the flow is ever refactored.

♻️ Proposed guard before publish operations
       appVersionId = await getReleaseCandidateVersionId({
         platform,
         publishProfileId
       })
     }
 
+    if (!appVersionId) {
+      core.setFailed('No app version ID resolved for publishing.')
+      return
+    }
+
     const publishId = await getPublishId({
       platform,
       publishProfileId,
-      appVersionId: appVersionId as string
+      appVersionId
     })
     await startPublish({ platform, publishProfileId, publishId })
     console.log(`Publish flow started for profile '${publishProfile}'.`)
 
     const success = await pollPublishStatus({
       platform,
       publishProfileId,
-      appVersionId: appVersionId as string
+      appVersionId
     })

Also applies to: 138-142

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main.ts` around lines 130 - 134, The publish flow in main.ts is using
`appVersionId as string` in the `getPublishId` call and the later publish
operation, which bypasses type safety. Replace these assertions with an explicit
guard in the surrounding publish logic (near the `appVersionId` assignment paths
and the `getPublishId` invocation) so the code narrows `appVersionId` before use
and fails early if it is still missing. Keep the fix localized to the publish
branch and ensure both affected call sites use the guarded value instead of a
cast.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@action.yml`:
- Around line 52-54: The current runtime validation in src/main.ts treats
appPath as one shared extension list, which allows invalid iOS/Android file
combinations to pass. Update the upload/appPath validation logic to branch on
platform and enforce .ipa for iOS and .apk/.aab for Android, matching the
contract documented in action.yml. Keep the check in the existing appPath
validation path so the correct platform-specific error is raised before upload
proceeds.

In `@src/api/publishApi.ts`:
- Around line 294-301: The publish flow lookup in the `getPublishId` path
currently assumes `steps[0]` has the `publishId`, which fails when the first
step is metadata-only or missing it. Update the logic to scan the `steps` array
for the first step with a valid `publishId` and return that value instead of
only checking the first element, while keeping the existing error path if no
step contains one.
- Around line 368-376: Update the polling/result handling in publishApi’s status
check so that the publish flow treats terminal statuses 2, 3, and 201 as
immediate failures alongside the existing 1 case. In the logic around the status
variable, return false as soon as these terminal cancelled/timeout/stopped
states are seen, and make sure the polling loop exits instead of waiting for the
full timeout. Keep the change localized to the status handling branch in
publishApi so the terminal state mapping stays consistent with the local status
model.
- Around line 144-154: The getLatestAppVersionId helper is relying on
versions[0], but getAppVersions does not guarantee newest-first ordering, so it
can return the wrong upload. Update getLatestAppVersionId to identify the newest
app version using a stable field like updateDate or creation/modified timestamp,
or preferably thread through the version id returned by the upload flow, so the
selection is deterministic regardless of list order.

---

Nitpick comments:
In `@src/main.ts`:
- Around line 130-134: The publish flow in main.ts is using `appVersionId as
string` in the `getPublishId` call and the later publish operation, which
bypasses type safety. Replace these assertions with an explicit guard in the
surrounding publish logic (near the `appVersionId` assignment paths and the
`getPublishId` invocation) so the code narrows `appVersionId` before use and
fails early if it is still missing. Keep the fix localized to the publish branch
and ensure both affected call sites use the guarded value instead of a cast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6f76b224-c4be-42e1-a087-95bbd232de59

📥 Commits

Reviewing files that changed from the base of the PR and between b9e2b9f and b9ef1fc.

⛔ Files ignored due to path filters (2)
  • dist/index.js is excluded by !**/dist/**
  • dist/index.js.map is excluded by !**/dist/**, !**/*.map
📒 Files selected for processing (5)
  • README.md
  • RELEASE_NOTE.md
  • action.yml
  • src/api/publishApi.ts
  • src/main.ts
💤 Files with no reviewable changes (1)
  • RELEASE_NOTE.md

Comment thread action.yml
Comment on lines 52 to +54
description:
'Specify the path to your application file. For iOS, this can be a .ipa
file path. For Android, specify the .apk or .aab file
path'
required: true
"Path to the application file. Required when 'upload' is true. For iOS use
a .ipa file; for Android use a .apk or .aab file."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Enforce the platform-specific appPath contract at runtime.

Line 53 documents .ipa for iOS and .apk/.aab for Android, but src/main.ts currently validates against one shared extension list, so invalid platform/file combinations can pass local validation and fail later.

Proposed validation shape
-      const validExtensions = ['.apk', '.aab', '.ipa']
+      const validExtensionsByPlatform: Record<string, string[]> = {
+        ios: ['.ipa'],
+        android: ['.apk', '.aab']
+      }
       const fileExtension = appPath
         .slice(appPath.lastIndexOf('.'))
         .toLowerCase()
-      if (!validExtensions.includes(fileExtension)) {
+      if (!validExtensionsByPlatform[platform].includes(fileExtension)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@action.yml` around lines 52 - 54, The current runtime validation in
src/main.ts treats appPath as one shared extension list, which allows invalid
iOS/Android file combinations to pass. Update the upload/appPath validation
logic to branch on platform and enforce .ipa for iOS and .apk/.aab for Android,
matching the contract documented in action.yml. Keep the check in the existing
appPath validation path so the correct platform-specific error is raised before
upload proceeds.

Comment thread src/api/publishApi.ts
Comment on lines +144 to +154
// The most recently created app version (first item) — used after an upload to
// identify the version that was just created.
export async function getLatestAppVersionId(options: {
platform: string
publishProfileId: string
}): Promise<string> {
const versions = await getAppVersions(options)
if (!versions.length) {
throw new Error('No app versions found on the publish profile after upload.')
}
return versions[0].id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect tests/docs/usages for an explicit newest-first contract or returned appVersionId.
rg -n -C3 'getLatestAppVersionId|app-versions|created|createdAt|appVersionId|taskId' .

Repository: appcircleio/appcircle-publish-githubaction

Length of output: 50400


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant API file and inspect the exact implementation.
ast-grep outline src/api/publishApi.ts --view expanded || true
sed -n '130,170p' src/api/publishApi.ts

# Look for any explicit contract about ordering or a returned version id.
rg -n -C2 'app-versions|newest-first|first item|appVersionId|version id|createdAt|created at|taskId|releaseCandidate' src test tests docs README.md .github || true

# Inspect the upload / publish flow around the suspect call site.
sed -n '90,150p' src/main.ts

Repository: appcircleio/appcircle-publish-githubaction

Length of output: 11244


🌐 Web query:

Appcircle publish v2 app-versions ordering newest first upload response appVersionId commit taskId

💡 Result:

The Appcircle API, specifically via the /v2/profiles/{profileId}/app-versions endpoint, allows you to retrieve a list of app versions associated with a specific Enterprise App Store profile [1][2]. Regarding your specific requirements: Ordering and Metadata: The Appcircle API response for app versions typically provides a list of objects containing version details [1]. While the API documentation does not explicitly detail a "newest first" query parameter for the endpoint, you can identify the latest versions by parsing the returned data [1]. The response objects generally include fields such as id (appVersionId), version string (e.g., CFBundleShortVersionString), and updateDate, which you can use to sort or filter the list programmatically [1][3]. Commit and Task Information: The core /app-versions API endpoint primarily focuses on versioning and metadata relevant to the Enterprise App Store (such as publish status and version numbers) [1][3]. Detailed build-specific information, such as associated commit hashes or specific task IDs, is typically accessed through the Build History or Build Detail endpoints rather than the store-specific app-versions list [4][5]. To retrieve this information, you should: 1. Use the /v2/profiles/{profileId}/app-versions endpoint to list the available versions [1][2]. 2. Iterate through the results and compare version strings or update timestamps to identify the newest version [1]. 3. If specific commit or task information is required for a build, use the Build History API (e.g., /builds or similar endpoints found in the Appcircle API documentation) to map build IDs to those specific details [4]. For the most accurate and up-to-date schema definitions, consult the interactive Swagger/OpenAPI documentation provided by Appcircle directly within your organization's Appcircle portal [6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the upload/commit flow and the returned shapes.
sed -n '204,266p' src/api/publishApi.ts

# Search for any handling of upload/commit response fields that could already expose a version id.
rg -n -C2 'commitResponse|uploadResponse|taskId|appVersionId|fileId|fileName|releaseCandidate' src/api/publishApi.ts src/main.ts

Repository: appcircleio/appcircle-publish-githubaction

Length of output: 14461


Don't rely on versions[0] here
The /app-versions list has no explicit newest-first contract, so this can pick an older upload and publish the wrong binary. Select the new version by a stable field such as updateDate/creation time, or use a version id returned from the upload flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/publishApi.ts` around lines 144 - 154, The getLatestAppVersionId
helper is relying on versions[0], but getAppVersions does not guarantee
newest-first ordering, so it can return the wrong upload. Update
getLatestAppVersionId to identify the newest app version using a stable field
like updateDate or creation/modified timestamp, or preferably thread through the
version id returned by the upload flow, so the selection is deterministic
regardless of list order.

Comment thread src/api/publishApi.ts
Comment on lines +294 to +301
const steps = response.data?.steps ?? []
const publishId = steps[0]?.publishId
if (!publishId) {
throw new Error(
'No publish flow steps found for the app version. Configure a publish flow on the profile first.'
)
}
return publishId

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Find the first available publishId instead of assuming it is on the first step.

If the first step is metadata-only or missing publishId, this throws even when later steps contain the run id.

Proposed fix
   const steps = response.data?.steps ?? []
-  const publishId = steps[0]?.publishId
+  const publishId = steps.find((step: any) => step?.publishId)?.publishId
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const steps = response.data?.steps ?? []
const publishId = steps[0]?.publishId
if (!publishId) {
throw new Error(
'No publish flow steps found for the app version. Configure a publish flow on the profile first.'
)
}
return publishId
const steps = response.data?.steps ?? []
const publishId = steps.find((step: any) => step?.publishId)?.publishId
if (!publishId) {
throw new Error(
'No publish flow steps found for the app version. Configure a publish flow on the profile first.'
)
}
return publishId
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/publishApi.ts` around lines 294 - 301, The publish flow lookup in the
`getPublishId` path currently assumes `steps[0]` has the `publishId`, which
fails when the first step is metadata-only or missing it. Update the logic to
scan the `steps` array for the first step with a valid `publishId` and return
that value instead of only checking the first element, while keeping the
existing error path if no step contains one.

Comment thread src/api/publishApi.ts
Comment on lines +368 to +376
const status = typeof data.status === 'number' ? data.status : 99
if (status === 0) {
console.log('Publish completed successfully.')
return true
}
if (status === 1) {
console.log('Publish failed.')
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Treat cancelled/timeout/stopped publish statuses as terminal failures.

The local status model marks 2, 3, and 201 as terminal, but the polling loop only exits for top-level 0 and 1. A cancelled or timed-out publish can wait until the 20-minute polling timeout and report the wrong failure reason.

Proposed fix
     if (status === 0) {
       console.log('Publish completed successfully.')
       return true
     }
-    if (status === 1) {
-      console.log('Publish failed.')
+    if ([1, 2, 3, 201].includes(status)) {
+      console.log(`Publish failed: ${stepStatusName(status)}.`)
       return false
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const status = typeof data.status === 'number' ? data.status : 99
if (status === 0) {
console.log('Publish completed successfully.')
return true
}
if (status === 1) {
console.log('Publish failed.')
return false
}
const status = typeof data.status === 'number' ? data.status : 99
if (status === 0) {
console.log('Publish completed successfully.')
return true
}
if ([1, 2, 3, 201].includes(status)) {
console.log(`Publish failed: ${stepStatusName(status)}.`)
return false
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/publishApi.ts` around lines 368 - 376, Update the polling/result
handling in publishApi’s status check so that the publish flow treats terminal
statuses 2, 3, and 201 as immediate failures alongside the existing 1 case. In
the logic around the status variable, return false as soon as these terminal
cancelled/timeout/stopped states are seen, and make sure the polling loop exits
instead of waiting for the full timeout. Keep the change localized to the status
handling branch in publishApi so the terminal state mapping stays consistent
with the local status model.

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.

2 participants