It also supports the command line tools. I only use fork in terminal to open the current folder in fork app. It’s quite useful when you are working on terminal with claude code.
When you faced this issue, You need to check next version of the xcdatamodel.
Case 2. LightWeight Migration
Most common crash issues are caused by mismatching options in a properties. For example you have a Binary Data type field with external storage. And when your next xcdatamodel doesn’t matching with external storage options, it causes crash issues
Lastly I recommend adding Arguments to investigate issues
// swift-tools-version:6.0
import PackageDescription
let package = Package(
name: "TestServer",
platforms: [
.macOS(.v13)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.111.0"),
.package(url: "https://github.com/vapor/fluent", from: "4.12.0"),
.package(url: "https://github.com/vapor/fluent-sqlite-driver", from: "4.8.0"),
.package(url: "https://github.com/vapor/sql-kit", from: "3.33.2"),
.package(url: "https://github.com/lukaskubanek/LoremSwiftum", from: "2.2.3"),
.package(url: "https://github.com/vapor/fluent-postgres-driver", from:"2.10.0"),
.package(url: "https://github.com/vapor/jwt", from: "5.1.2"),
.package(url: "https://github.com/vapor/queues-redis-driver.git", from: "1.0.0"),
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Vapor", package: "vapor"),
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
.product(name: "SQLKit", package: "sql-kit"),
.product(name: "LoremSwiftum", package: "LoremSwiftum"),
.product(name: "JWT", package: "jwt"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "QueuesRedisDriver", package: "queues-redis-driver")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
.executableTarget(name: "Run", dependencies: [
.target(name: "App")
]
),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor")
])
]
)
Create an AsyncScheduledJob
import Foundation
import Vapor
import Queues
struct ScheduledJobs: AsyncScheduledJob {
// Add extra services here via dependency injection, if you need them.
func run(context: QueueContext) async throws {
context.logger.info("Starting ScheduledJobs")
print("✅ It is called")
//Call other services using context.application.client
// context.application.client
context.logger.info("ScheduledJobs completed")
}
}
Hope my articles helps you who want to run scheduled job using Redis. Please like my post or leave a comment it helps me continue share my knowledge for free.
This post is for whom want to use AWS Lambda with OpenAPI Generator. Official guide is useful but I felt there are some missing information. So I wrote this post. You can successfully run AWS Lambda function on your local machine and debug your code.
Let’s start from very simple example. You only need 4 files. I’ll explain details. (Ignore Tests folder, no need it in this tutorial)
Package.swift
NativeMobileServer.swift
openapi.yaml
openapi-generator-config.yaml
Step 1. Define OpenAPI Spec
This OpenAPI spec is for tutorial.
Please check folder and file structure. Create an openapi.yaml
openapi: 3.1.0
info:
title: MobileJobService
version: 1.0.0
paths:
/jobs/fetch:
post:
summary: Fetch job data from external source
description: >
This endpoint is called by a scheduled Lambda or backend service.
It fetches job data from the given URL and processes it using the provided prompt.
operationId: fetchJobs
tags:
- jobs
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FetchJobsRequest'
responses:
'200':
description: Successfully fetched and processed job data
content:
application/json:
schema:
$ref: '#/components/schemas/JobListResponse'
'400':
description: Invalid input parameters
'500':
description: Internal error during job fetch or processing
components:
schemas:
FetchJobsRequest:
type: object
required:
- url
- prompt
properties:
url:
type: string
format: uri
description: Target URL to scrape or fetch job data from
prompt:
type: string
description: Instruction / extraction prompt used to parse the fetched page
JobListResponse:
type: array
items:
$ref: '#/components/schemas/Job'
Job:
type: object
required:
- id
- title
properties:
id:
type: string
description: Unique identifier for the job
title:
type: string
description: Job title
country:
type: string
description: Country code (e.g. SG, US, TW)
city:
type: string
description: City name (e.g. Singapore)
postedAt:
type: string
format: date-time
description: When this job was posted, if known
company:
type: string
description: Company name
team:
type: string
description: Team / department (e.g. Mobile, Backend, Growth)
jobDescriptionLink:
type: string
format: uri
description: Public link to full job description
jobApplyLink:
type: string
format: uri
description: Public link to apply
salary:
$ref: '#/components/schemas/Salary'
description:
type: string
description: Cleaned / extracted full-text description for the role
Salary:
type: object
properties:
min:
type: number
description: Minimum compensation
max:
type: number
description: Maximum compensation
basis:
type: string
enum: [year, month]
description: Salary period basis (yearly or monthly)
And I can see the results from AWS Lambda function
Conclusion
Swift is very powerful for developing server-side applications. There a lot of great open source projects. In Part 2, I’ll explain how to deploy AWS Lambda Swift function to the AWS using SAM CLI.
Swift Format is made by Apple. If your Xcode Version is latest version (after Xcode 16), you don’t need to install it. Toolchain contains swift format.
When you create a PR that targets main branch, our GitHub action will run and comment results on your Opened PR.
IBM OpenAPI Validator provides very detailed information. To fix issues, You can update your OpenAPI Spec file or You can change the rulesets if you don’t want to change your OpenAPI Spec files.
BTW This validator is really helpful it prevent wrong OpenAPI spec merged into main branch.
Don’t select template (e.g, Next.js, Due, Angular and Vite. We don’t need it)
And Select your GitHub Repository and Branch. (You don’t need to make your Repo as Public, Private Repo also is working fine)
Protect your site if you want
Set an Username and Password
Ok, that’s all. Click Save and deploy!
Click Monitoring and check your Domain. Open this url.
If you set Username and Password, You must Sign In to access your Website
All done, Your OpenAPI Document Site is Live now!
Step 3. Setup Domain
If you want to set your custom domain for your website, follow this guidelines
I recommend Route53. If your domain already registered in Route53, setup custom domain is very easy.
Enter your subdomains. And Click Add domain button.
It takes 2-3 minutes. Just wait a bit. You will access your static website using your subdomain.
Conclusion
Using Amplify is super simple to deploy the static website. You don’t need to extra setup. When your branch has updated, amplify will automatically detect that changes and deploy it.
Testing App Launch Time for React Native Sample App – Expo
Create Sample App using Expo
When you create an app using Expo, there are no iOS and Android folder.
Create iOS and Android folder in Expo Sample Project
npx expo prebuild
Setup iOS App Launch Tests
Add UI Testing Bundle and write a test cases
@MainActor
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
@MainActor
func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
// This measures how long it takes to launch your application.
let measureOptions = XCTMeasureOptions()
measureOptions.iterationCount = 10
measure(metrics: [XCTApplicationLaunchMetric()], options: measureOptions) {
XCUIApplication().launch()
}
}
}
Results
I ran 10 times and it’s average launch time is 0.157s (157ms).
Setting GitHub actions is a headache, and it takes time to run correctly. I’ll share what actions I daily use.
How to add github actions?
Add github actions on your branch
.github/workflows/xxxx.yml
Trigger github action by leaving a comment on PR
Scenario 1: share new build to someone
You can define commands to run action
For example, If you want to share something to test, use this action.
share is command
test is userId
And you can leave a comment using github.issues.createComment
This action is very useful. You can integrate third-party services like Slack, WhatsApp, or Linear. Listening share command and trigger action whatever you want to share it.
name: Comment Action
on:
issue_comment:
types: [created]
jobs:
comment_job:
runs-on: ubuntu-latest
steps:
- name: Check Comment Type
id: check_comment
uses: actions/github-script@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const comment = context.payload.comment.body.trim();
console.log(`Received comment: ${comment}`);
const issueOrPrNumber = context.payload.issue?.number || context.payload.pull_request?.number;
if (!issueOrPrNumber) {
throw new Error("Could not determine issue or PR number.");
}
let action = '';
if (comment.startsWith('share')) {
action = 'share';
}
core.setOutput('action', action);
core.setOutput('comment', comment);
core.setOutput('issue_or_pr_number', issueOrPrNumber);
- name: Handle Share Command
if: steps.check_comment.outputs.action == 'share'
uses: actions/github-script@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const comment = '${{ steps.check_comment.outputs.comment }}';
const issueOrPrNumber = '${{ steps.check_comment.outputs.issue_or_pr_number }}';
if (!issueOrPrNumber) {
throw new Error("Could not determine the issue or PR number.");
}
const splitComment = comment.split(' ');
if (splitComment.length < 2) {
throw new Error("Invalid 'share' command format. Expected: 'share <id>'");
}
const recipientId = splitComment[1]; // Extract ID after "share"
const commentBody = `Sharing this with: ${recipientId}`;
console.log(`Adding a share comment for ID: ${recipientId}`);
await github.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueOrPrNumber,
body: commentBody
});
scenario 2: rebuild when the build failed
There are 2 yml files in workflows
When you get a build failed message, you can rebuild it by leaving a comment.
You must be logged in to post a comment.