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
105 changes: 80 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
## Appcircle Publish

Upload an application binary (`.ipa`, `.apk`, or `.aab`) directly to an Appcircle
**Publish** profile from your GitHub workflow. The uploaded binary becomes a new
app version on the target Publish profile, ready for the profile's configured
app store publishing flow.
Upload an application binary to an Appcircle **Publish** profile and/or trigger
its publish flow (app store publishing) directly from your GitHub workflow.

Learn more about
[Appcircle Publish](https://appcircle.io/publish-mobile-app?utm_source=github&utm_medium=plugin&utm_campaign=publish).
[Appcircle Publish](https://appcircle.io/publish-to-stores?utm_source=github&utm_medium=plugin&utm_campaign=publish).

### System Requirements

Expand All @@ -31,33 +29,90 @@ To generate a Personal API Token:

![Token Generation](images/PAT.png)

## What the action does

The action has two independent switches — `upload` and `publish` — both default
to `false`. **You must enable at least one.** Create the Publish profile in
Appcircle first; the action targets it by name (profile names are unique per
platform).

| `upload` | `publish` | Behavior |
|:--------:|:---------:|----------|
| `true` | `false` | Upload `appPath` as a new app version on the profile. |
| `false` | `true` | Trigger the publish flow for the profile's **current release candidate**. |
| `true` | `true` | Upload `appPath`, **mark the new version as release candidate**, then trigger the publish flow for it. |
| `false` | `false` | Error — nothing to do. |

**Rules:**

- **In-progress guard:** if a publish is already running for the target profile,
the action does **not** start a new one and fails fast.
- **Release candidate:** when both `upload` and `publish` are `true`, the freshly
uploaded version is automatically marked as the release candidate before it is
published. In publish-only mode, the profile's existing release candidate is
published.
- **Progress:** while publishing, the action polls the publish status and prints
step-by-step progress until the flow succeeds or fails.

> **Manual-approval steps:** if the profile's publish flow contains a manual step
> (e.g. "Get Approval via Email"), the flow will wait for that action and the
> plugin will keep polling until it completes or the poll times out. For CI use,
> prefer publish flows without manual gates.

## How to use Appcircle Publish Action

This action uploads a binary to an existing Publish profile. Create the Publish
profile in Appcircle first, then reference it by name. Publish profile names are
unique per platform.
**Upload only:**

```yml
- name: Upload App to Appcircle Publish
id: upload-to-appcircle-publish
- name: Upload to Appcircle Publish
uses: appcircleio/appcircle-publish-githubaction
with:
personalAPIToken: ${{ secrets.AC_PERSONAL_API_TOKEN }}
platform: PLATFORM # "ios" or "android"
platform: ios # or android
publishProfile: PUBLISH_PROFILE_NAME
appPath: APP_PATH
upload: 'true'
appPath: ./app.ipa
```

- `personalAPIToken`: The Appcircle Personal API token is utilized to
authenticate and secure access to Appcircle services, ensuring that only
authorized users can perform actions within the platform.
- `platform`: Target platform of the Publish profile. Must be `ios` or
**Publish only (publishes the profile's current release candidate):**

```yml
- name: Trigger Appcircle Publish
uses: appcircleio/appcircle-publish-githubaction
with:
personalAPIToken: ${{ secrets.AC_PERSONAL_API_TOKEN }}
platform: ios
publishProfile: PUBLISH_PROFILE_NAME
publish: 'true'
```

**Upload and publish (uploads, marks it release candidate, then publishes):**

```yml
- name: Upload and Publish to Appcircle
uses: appcircleio/appcircle-publish-githubaction
with:
personalAPIToken: ${{ secrets.AC_PERSONAL_API_TOKEN }}
platform: android
publishProfile: PUBLISH_PROFILE_NAME
upload: 'true'
publish: 'true'
appPath: ./app.aab
```

### Inputs

- `personalAPIToken` (required): Appcircle Personal API Token used to
authenticate and secure access to Appcircle services.
- `platform` (required): Target platform of the Publish profile — `ios` or
`android`.
- `publishProfile`: Name of the Publish profile to upload the binary to. The
name is resolved to the profile for the selected platform.
- `appPath`: Indicates the file path to the application that will be uploaded to
the Appcircle Publish profile. For iOS use a `.ipa` file; for Android use an
`.apk` or `.aab` file.
- `publishProfile` (required): Name of the Publish profile to target. Resolved to
the profile for the selected platform.
- `upload` (optional, default `false`): Upload `appPath` as a new app version.
- `publish` (optional, default `false`): Trigger the profile's publish flow.
- `appPath` (required when `upload` is `true`): Path to the application file. For
iOS use a `.ipa` file; for Android use a `.apk` or `.aab` file.
- `authEndpoint` / `apiEndpoint` (optional): self-hosted endpoints — see below.

### Self-Hosted Appcircle

Expand All @@ -68,13 +123,13 @@ they default to the Appcircle cloud (`https://auth.appcircle.io` and
change.

```yml
- name: Upload App to Appcircle Publish
- name: Trigger Appcircle Publish
uses: appcircleio/appcircle-publish-githubaction
with:
personalAPIToken: ${{ secrets.AC_PERSONAL_API_TOKEN }}
platform: PLATFORM # "ios" or "android"
platform: ios
publishProfile: PUBLISH_PROFILE_NAME
appPath: APP_PATH
publish: 'true'
authEndpoint: https://auth.your-appcircle-domain.com
apiEndpoint: https://api.your-appcircle-domain.com
```
Expand Down Expand Up @@ -106,4 +161,4 @@ projects, please
### Reference

For more detailed instructions and support, visit the
[Appcircle Publish documentation](https://appcircle.io/publish-mobile-app?utm_source=github&utm_medium=plugin&utm_campaign=publish).
[Appcircle Publish documentation](https://appcircle.io/publish-to-stores?utm_source=github&utm_medium=plugin&utm_campaign=publish).
34 changes: 0 additions & 34 deletions RELEASE_NOTE.md

This file was deleted.

30 changes: 23 additions & 7 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: 'Appcircle Publish'
author: 'appcircleio'
description: 'Upload an application binary to an Appcircle Publish profile.'
description:
'Upload a binary to an Appcircle Publish profile and/or trigger its publish
flow.'

branding:
icon: 'upload-cloud'
Expand Down Expand Up @@ -28,15 +30,29 @@ inputs:
required: true
publishProfile:
description:
'Name of the Publish profile to upload the binary to. Profile names are
unique per platform.'
'Name of the Publish profile to target. Profile names are unique per
platform.'
required: true
upload:
description:
"Upload the binary at 'appPath' as a new app version on the profile.
Defaults to false. At least one of 'upload' or 'publish' must be true."
required: false
default: 'false'
publish:
description:
"Trigger the profile's publish flow. Defaults to false. When both 'upload'
and 'publish' are true, the freshly uploaded version is marked as release
candidate and published; when only 'publish' is true, the profile's
current release candidate is published. A new publish is never started if
one is already in progress for the profile."
required: false
default: 'false'
appPath:
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."
Comment on lines 52 to +54

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.

required: false
runs:
using: 'node20'
main: 'dist/index.js'
Loading
Loading