Add releases
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
name: Bug Report
|
||||||
|
about: Create a report to help us fix an issue with a3270
|
||||||
|
title: "[BUG] "
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to report an issue!
|
||||||
|
- type: input
|
||||||
|
id: host_environment
|
||||||
|
attributes:
|
||||||
|
label: Host Environment
|
||||||
|
description: What mainframe / operating system was connected (e.g., z/OS, z/VM, CMS, TSO, MVS 3.8j, Hercules/TK4-)?
|
||||||
|
placeholder: "e.g. z/VM 7.2 CMS, Hercules TK4-"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: android_device
|
||||||
|
attributes:
|
||||||
|
label: Android Device & OS Version
|
||||||
|
description: What Android device and Android version are you using?
|
||||||
|
placeholder: "e.g. Pixel 8, Android 14 (API 34)"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: dropdown
|
||||||
|
id: terminal_model
|
||||||
|
attributes:
|
||||||
|
label: Terminal Model
|
||||||
|
description: Terminal model in use
|
||||||
|
options:
|
||||||
|
- 3279-2 (Color 24x80)
|
||||||
|
- 3279-3 (Color 32x80)
|
||||||
|
- 3279-4 (Color 43x80)
|
||||||
|
- 3279-5 (Color 27x132)
|
||||||
|
- 3278 (Monochrome)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Problem Description
|
||||||
|
description: A clear and concise description of what went wrong.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: Steps To Reproduce
|
||||||
|
description: Steps to reproduce the behavior.
|
||||||
|
placeholder: |
|
||||||
|
1. Connect to host '...'
|
||||||
|
2. Open File Transfer dialog
|
||||||
|
3. Start IND$FILE GET ...
|
||||||
|
4. See error ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Logs / Logcat Output
|
||||||
|
description: Paste any logcat or debug logs here.
|
||||||
|
render: shell
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: Feature Request
|
||||||
|
about: Suggest an idea or enhancement for a3270
|
||||||
|
title: "[FEATURE] "
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for suggesting a feature or enhancement for a3270!
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: Is your feature request related to a problem?
|
||||||
|
description: A clear and concise description of what the problem or missing capability is.
|
||||||
|
placeholder: "I'm always frustrated when [...]"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Describe the solution you'd like
|
||||||
|
description: A clear and concise description of what you want to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Describe alternatives you've considered
|
||||||
|
description: Any alternative solutions or features you've considered.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
name: Build and Test a3270
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main", "master", "develop" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main", "master" ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Android APK
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Configure Dynamic DNS Resolvers
|
||||||
|
run: |
|
||||||
|
printf "nameserver 1.1.1.1\nnameserver 8.8.8.8\n" > /etc/resolv.conf 2>/dev/null || true
|
||||||
|
echo "64.22.43.251 git.hugfreevikings.wtf" | sudo tee -a /etc/hosts || echo "64.22.43.251 git.hugfreevikings.wtf" >> /etc/hosts || true
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Checkout j3270 (for lib3270j)
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://git.hugfreevikings.wtf/rudi/j3270.git j3270
|
||||||
|
|
||||||
|
- name: Set up Java JDK (Temurin 21)
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
java-version: '21'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Set up Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Make scripts executable
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew ./build.sh
|
||||||
|
|
||||||
|
- name: Build Android APK
|
||||||
|
run: |
|
||||||
|
./gradlew assembleDebug --no-daemon
|
||||||
|
env:
|
||||||
|
J3270_DIR: ${{ github.workspace }}/j3270
|
||||||
|
|
||||||
|
- name: Upload a3270 APK Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
name: a3270-debug
|
||||||
|
path: build/outputs/apk/debug/a3270-debug.apk
|
||||||
|
|
||||||
|
- name: Report Build Status
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "### ❌ Build Failed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Please check the runner logs above for details." >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
name: Build a3270 APK
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build Android APK
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Configure DNS and Hosts
|
|
||||||
run: |
|
|
||||||
echo "64.22.43.251 git.hugfreevikings.wtf" | sudo tee -a /etc/hosts || echo "64.22.43.251 git.hugfreevikings.wtf" >> /etc/hosts || true
|
|
||||||
echo "nameserver 1.1.1.1" | sudo tee -a /etc/resolv.conf || echo "nameserver 1.1.1.1" >> /etc/resolv.conf || true
|
|
||||||
echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf || echo "nameserver 8.8.8.8" >> /etc/resolv.conf || true
|
|
||||||
|
|
||||||
- name: Checkout a3270
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Checkout j3270 (for lib3270j)
|
|
||||||
run: |
|
|
||||||
git clone --depth 1 https://git.hugfreevikings.wtf/rudi/j3270.git j3270
|
|
||||||
|
|
||||||
- name: Set up JDK 21
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '21'
|
|
||||||
|
|
||||||
- name: Set up Android SDK
|
|
||||||
uses: android-actions/setup-android@v3
|
|
||||||
|
|
||||||
- name: Grant execute permission for gradlew
|
|
||||||
run: chmod +x gradlew
|
|
||||||
|
|
||||||
- name: Build Debug APK
|
|
||||||
run: ./gradlew assembleDebug --no-daemon
|
|
||||||
env:
|
|
||||||
J3270_DIR: ${{ github.workspace }}/j3270
|
|
||||||
|
|
||||||
- name: Upload APK Artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: a3270-debug
|
|
||||||
path: build/outputs/apk/debug/a3270-debug.apk
|
|
||||||
if-no-files-found: error
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
name: Release a3270
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Build & Publish Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Configure Dynamic DNS Resolvers
|
||||||
|
run: |
|
||||||
|
printf "nameserver 1.1.1.1\nnameserver 8.8.8.8\n" > /etc/resolv.conf 2>/dev/null || true
|
||||||
|
echo "64.22.43.251 git.hugfreevikings.wtf" | sudo tee -a /etc/hosts || echo "64.22.43.251 git.hugfreevikings.wtf" >> /etc/hosts || true
|
||||||
|
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Checkout j3270 (for lib3270j)
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://git.hugfreevikings.wtf/rudi/j3270.git j3270
|
||||||
|
|
||||||
|
- name: Set up Java JDK (Temurin 21)
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
java-version: '21'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Set up Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
|
- name: Make scripts executable
|
||||||
|
run: |
|
||||||
|
chmod +x ./gradlew ./build.sh
|
||||||
|
|
||||||
|
- name: Build Android APK
|
||||||
|
run: |
|
||||||
|
./gradlew assembleDebug --no-daemon
|
||||||
|
env:
|
||||||
|
J3270_DIR: ${{ github.workspace }}/j3270
|
||||||
|
|
||||||
|
- name: Upload Release Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
name: a3270-${{ github.ref_name }}
|
||||||
|
path: build/outputs/apk/debug/a3270-debug.apk
|
||||||
|
|
||||||
|
- name: Publish Release to Gitea
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
TAG="${{ github.ref_name }}"
|
||||||
|
API_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
|
||||||
|
TOKEN="${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
APK_FILE="build/outputs/apk/debug/a3270-debug.apk"
|
||||||
|
|
||||||
|
IS_PRERELEASE="false"
|
||||||
|
case "$TAG" in
|
||||||
|
*beta*|*alpha*|*rc*|*pre*|*preview*|*dev*)
|
||||||
|
IS_PRERELEASE="true"
|
||||||
|
echo "Tag $TAG detected as pre-release / beta."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Creating Release for tag $TAG (prerelease=$IS_PRERELEASE)..."
|
||||||
|
RESPONSE=$(curl -s -X POST "$API_URL" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"tag_name\": \"$TAG\", \"name\": \"a3270 $TAG\", \"body\": \"Automated release for **$TAG**.\n\n### Installing a3270\n```bash\nadb install -r a3270.apk\n```\", \"draft\": false, \"prerelease\": $IS_PRERELEASE}")
|
||||||
|
|
||||||
|
RELEASE_ID=$(echo "$RESPONSE" | grep -o '"id":[0-9]*' | head -n 1 | cut -d':' -f2)
|
||||||
|
|
||||||
|
if [ -n "$RELEASE_ID" ] && [ -f "$APK_FILE" ]; then
|
||||||
|
echo "Uploading $APK_FILE to release $RELEASE_ID as a3270.apk..."
|
||||||
|
curl -s -X POST "$API_URL/$RELEASE_ID/assets?name=a3270.apk" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/vnd.android.package-archive" \
|
||||||
|
--data-binary @"$APK_FILE"
|
||||||
|
echo "Release $TAG published with a3270.apk attached successfully!"
|
||||||
|
else
|
||||||
|
echo "Release API response: $RESPONSE"
|
||||||
|
fi
|
||||||
@@ -1,33 +1,64 @@
|
|||||||
# a3270
|
# a3270
|
||||||
|
|
||||||
An Android TN3270 terminal emulator based on `lib3270j` / `j3270`, built with Jetpack Compose and ported using AI.
|
[](https://git.hugfreevikings.wtf/rudi/a3270/actions)
|
||||||
|
[](https://git.hugfreevikings.wtf/rudi/a3270/releases)
|
||||||
|
[](https://developer.android.com)
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
## Repositories
|
An **x3270-aligned IBM 3270 mainframe terminal emulator for Android**, written in Kotlin using **Jetpack Compose** and powered by the `lib3270j` protocol engine from [j3270](https://git.hugfreevikings.wtf/rudi/j3270). Designed for mobile access to IBM z/OS, z/VM, CMS, and TSO systems over TN3270 and TN3270E.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Repositories
|
||||||
|
|
||||||
- **a3270 (Android App)**: https://git.hugfreevikings.wtf/rudi/a3270
|
- **a3270 (Android App)**: https://git.hugfreevikings.wtf/rudi/a3270
|
||||||
- **j3270 (Desktop App & `lib3270j` Core Library)**: https://git.hugfreevikings.wtf/rudi/j3270
|
- **j3270 (Desktop App & `lib3270j` Core Library)**: https://git.hugfreevikings.wtf/rudi/j3270
|
||||||
|
|
||||||
`a3270` relies on the shared 3270 protocol library (`lib3270j`) provided by the `j3270` repository.
|
`a3270` relies on the shared 3270 protocol library (`lib3270j`) provided by the `j3270` repository.
|
||||||
|
|
||||||
## CI/CD & Automated Builds
|
---
|
||||||
|
|
||||||
Automated CI/CD is configured using Gitea Actions (`.gitea/workflows/build.yml`). On every push to `main` or pull request, the workflow automatically:
|
## 🚀 Quick Download & Install
|
||||||
1. Clones `a3270` and `j3270` (`lib3270j`).
|
|
||||||
2. Configures JDK 21 and the Android SDK.
|
|
||||||
3. Builds the debug APK (`a3270-debug.apk`).
|
|
||||||
4. Uploads the resulting APK as a downloadable workflow artifact (`a3270-debug`).
|
|
||||||
|
|
||||||
You can download pre-built APKs directly from the **Actions** tab of the repository on Gitea.
|
### Latest Standalone APK
|
||||||
|
You can download ready-to-install Android APKs directly from releases or CI builds:
|
||||||
|
|
||||||
## Prerequisites
|
- **[Download Latest Tagged Release (`a3270.apk`)](https://git.hugfreevikings.wtf/rudi/a3270/releases)**
|
||||||
|
- **[Latest Nightly CI Artifacts](https://git.hugfreevikings.wtf/rudi/a3270/actions)** (Download under the latest successful workflow run)
|
||||||
|
|
||||||
|
### Installing `a3270`
|
||||||
|
To install the APK on a connected Android device or emulator via `adb`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb install -r a3270.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- **Modern Jetpack Compose UI**: Responsive, touch-optimized 3270 terminal screen rendering.
|
||||||
|
- **TN3270 & TN3270E Protocol Support**: RFC 2355 compliant state machine, negotiation, Device-Type query, and SSL/TLS encryption via `lib3270j`.
|
||||||
|
- **On-Screen Function Key Bar**: Quick-access touch bar for PF1–PF24, PA1–PA3, Enter, Clear, Reset, and Attn keys.
|
||||||
|
- **IND$FILE File Transfer**: Full mobile UI for **CUT** and **DFT (DDM)** high-speed structured field file transfers with ASCII/binary translation, CRLF handling, and recfm/lrecl formatting for TSO, VM/CMS, and CICS.
|
||||||
|
- **OIA Status Line**: Real-time Operator Information Area displaying connection state, keyboard lock, insert mode, cursor row/col, and LU name.
|
||||||
|
- **Host Profile Storage**: Save and manage multiple mainframe connection profiles with custom ports, models, and SSL/TLS options.
|
||||||
|
- **Background Session Persistence**: Android foreground service keeps your terminal session alive when multitasking.
|
||||||
|
- **Terminal Models**:
|
||||||
|
- Model 2 (24x80)
|
||||||
|
- Model 3 (32x80)
|
||||||
|
- Model 4 (43x80)
|
||||||
|
- Model 5 (27x132)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Building from Source
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
- **Java Development Kit (JDK)**: JDK 17 or JDK 21
|
- **Java Development Kit (JDK)**: JDK 17 or JDK 21
|
||||||
- **Android SDK**: Android SDK with API 34 platforms and build-tools installed (`ANDROID_HOME` or `ANDROID_SDK_ROOT` set)
|
- **Android SDK**: API 34 platforms and build-tools (`ANDROID_HOME` or `ANDROID_SDK_ROOT` set)
|
||||||
|
|
||||||
## Setup & Building
|
|
||||||
|
|
||||||
### 1. Clone Repositories Side-by-Side
|
### 1. Clone Repositories Side-by-Side
|
||||||
|
|
||||||
For the easiest setup, clone both `j3270` and `a3270` into the same parent folder:
|
For the easiest setup, clone both `j3270` and `a3270` into the same parent folder:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -46,15 +77,12 @@ cd a3270
|
|||||||
> ```
|
> ```
|
||||||
|
|
||||||
### 2. Build the Debug APK
|
### 2. Build the Debug APK
|
||||||
|
Using the helper script:
|
||||||
You can build using the helper script:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./build.sh
|
./build.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Or directly with Gradle Wrapper:
|
Or using Gradle Wrapper directly:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./gradlew assembleDebug
|
./gradlew assembleDebug
|
||||||
```
|
```
|
||||||
@@ -64,25 +92,50 @@ The compiled APK will be generated at:
|
|||||||
build/outputs/apk/debug/a3270-debug.apk
|
build/outputs/apk/debug/a3270-debug.apk
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deployment / Installation
|
---
|
||||||
|
|
||||||
To install the debug APK onto a connected Android device or emulator via `adb`:
|
## 🏷️ How to Tag & Publish (Beta) Releases
|
||||||
|
|
||||||
|
Releases can be published automatically to Gitea via Git tags:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
adb install -r build/outputs/apk/debug/a3270-debug.apk
|
# 1. Create a version tag (stable or beta)
|
||||||
|
git tag -a v0.1.0-beta.1 -m "Release v0.1.0-beta.1"
|
||||||
|
|
||||||
|
# Or a stable release:
|
||||||
|
git tag -a v0.1.0 -m "Release v0.1.0"
|
||||||
|
|
||||||
|
# 2. Push the tag to Gitea
|
||||||
|
git push origin v0.1.0-beta.1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Contributing
|
Pushing any `v*` tag triggers the automated release workflow (`.gitea/workflows/release.yaml`), which:
|
||||||
|
1. Automatically detects pre-releases (tags containing `beta`, `alpha`, `rc`, `pre`, `preview`, or `dev`) and marks them as **Pre-release** on Gitea.
|
||||||
|
2. Builds the APK and packages it.
|
||||||
|
3. Publishes a new Gitea Release with `a3270.apk` attached automatically.
|
||||||
|
|
||||||
Contributions are welcome!
|
---
|
||||||
|
|
||||||
|
## 🔍 Topics & Discoverability
|
||||||
|
|
||||||
|
Suggested keywords/topics for repository indexing:
|
||||||
|
`tn3270` · `tn3270e` · `ibm-3270` · `mainframe` · `terminal-emulator` · `android` · `android-app` · `jetpack-compose` · `kotlin` · `x3270` · `j3270` · `ind-file` · `file-transfer` · `ebcdic` · `z-vm` · `z-os` · `cms` · `tso` · `cics`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to open a bug report or feature request via the Gitea issue tracker.
|
||||||
|
|
||||||
I have contributed no code to this project, it was entirely written by LLMs with my guidance only.
|
I have contributed no code to this project, it was entirely written by LLMs with my guidance only.
|
||||||
|
|
||||||
## Acknowledgements
|
---
|
||||||
|
|
||||||
- [j3270](https://git.hugfreevikings.wtf/rudi/j3270)
|
## 📜 Acknowledgements
|
||||||
- [x3270](https://x3270.miraheze.org/wiki/Main_Page)
|
|
||||||
|
- [j3270](https://git.hugfreevikings.wtf/rudi/j3270) — Desktop emulator and `lib3270j` protocol engine
|
||||||
|
- [x3270](https://x3270.miraheze.org/wiki/Main_Page) — Reference C implementation and protocol specifications
|
||||||
- [Antigravity](https://antigravity.google)
|
- [Antigravity](https://antigravity.google)
|
||||||
- Claude Opus 4.6
|
- Claude Opus 4.6
|
||||||
- Gemini 3.1 Pro (High)
|
- Gemini 3.1 Pro
|
||||||
- Gemini 3.7 Flash (High)
|
- Gemini 3.7 Flash
|
||||||
|
|||||||
Reference in New Issue
Block a user