mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
- Implemented MonitorUtil for managing monitor secrets and populating them in monitor steps and tests. - Created StackTraceParser to parse and structure stack traces from various programming languages. - Developed SyslogParser to handle and parse syslog messages in both RFC 5424 and RFC 3164 formats.
1778 lines
64 KiB
YAML
1778 lines
64 KiB
YAML
name: Push Release Images to Docker Hub and GitHub Container Registry
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- "release"
|
|
workflow_dispatch:
|
|
inputs:
|
|
publish_android_to_store:
|
|
description: 'Publish Android app to Google Play Store'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
publish_ios_to_store:
|
|
description: 'Publish iOS app to App Store'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: write
|
|
packages: write
|
|
|
|
jobs:
|
|
generate-build-number:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
build_number: ${{ steps.buildnumber.outputs.build_number }}
|
|
steps:
|
|
- name: Generate build number
|
|
id: buildnumber
|
|
uses: onyxmueller/build-tag-number@v1.0.2
|
|
with:
|
|
token: ${{secrets.github_token}}
|
|
- run: echo "Build number is ${{ steps.buildnumber.outputs.build_number }}"
|
|
|
|
|
|
read-version:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
major_minor: ${{ steps.determine.outputs.semver_base }}
|
|
semver_base: ${{ steps.determine.outputs.semver_base }}
|
|
major: ${{ steps.determine.outputs.major }}
|
|
minor: ${{ steps.determine.outputs.minor }}
|
|
patch: ${{ steps.determine.outputs.patch }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
- name: Check version and verify not already released
|
|
id: determine
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
VERSION_RAW="$(tr -d ' \n' < VERSION)"
|
|
if [[ -z "$VERSION_RAW" ]]; then
|
|
echo "VERSION is empty" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Version from VERSION file: $VERSION_RAW"
|
|
|
|
IFS='.' read -r major minor patch <<< "$VERSION_RAW"
|
|
if [[ -z "$minor" ]]; then
|
|
echo "VERSION must contain major and minor components" >&2
|
|
exit 1
|
|
fi
|
|
patch="${patch:-0}"
|
|
|
|
for part_name in major minor patch; do
|
|
part="${!part_name}"
|
|
if ! [[ "$part" =~ ^[0-9]+$ ]]; then
|
|
echo "Invalid ${part_name} component '$part' in VERSION" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Check if this version is already released on GitHub
|
|
echo "Checking if version $VERSION_RAW is already released on GitHub..."
|
|
|
|
if gh release view "$VERSION_RAW" --repo "$REPOSITORY" &>/dev/null; then
|
|
echo "::error::Version $VERSION_RAW is already released on GitHub. Please update the VERSION file to a new version."
|
|
exit 1
|
|
fi
|
|
|
|
# Also check with 'v' prefix just in case
|
|
if gh release view "v$VERSION_RAW" --repo "$REPOSITORY" &>/dev/null; then
|
|
echo "::error::Version v$VERSION_RAW is already released on GitHub. Please update the VERSION file to a new version."
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Version $VERSION_RAW is not yet released. Proceeding with release."
|
|
|
|
echo "semver_base=${VERSION_RAW}" >> "$GITHUB_OUTPUT"
|
|
echo "major=${major}" >> "$GITHUB_OUTPUT"
|
|
echo "minor=${minor}" >> "$GITHUB_OUTPUT"
|
|
echo "patch=${patch}" >> "$GITHUB_OUTPUT"
|
|
echo "Using version: ${VERSION_RAW}"
|
|
|
|
|
|
|
|
helm-chart-deploy:
|
|
runs-on: ubuntu-latest
|
|
needs: [generate-build-number, read-version]
|
|
env:
|
|
CI_COMMIT_AUTHOR: Continuous Integration
|
|
steps:
|
|
|
|
- name: Install Helm
|
|
run: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Build and Package Helm chart
|
|
run: |
|
|
cd ..
|
|
echo '${{ secrets.GPG_PRIVATE_KEY }}' > private.key
|
|
gpg --import private.key || true
|
|
rm private.key
|
|
echo "GPG key imported successfully"
|
|
gpg --export-secret-keys >~/.gnupg/secring.gpg
|
|
echo "GPG key exported successfully"
|
|
eval `ssh-agent -s`
|
|
ssh-add - <<< '${{ secrets.HELM_CHART_GITHUB_REPO_DEPLOY_KEY }}'
|
|
git clone git@github.com:OneUptime/helm-chart.git
|
|
cd oneuptime/HelmChart/Public
|
|
helm lint oneuptime
|
|
helm template oneuptime --values oneuptime/values.yaml
|
|
helm package --sign --key 'key@oneuptime.com' --keyring ~/.gnupg/secring.gpg oneuptime --version ${{needs.read-version.outputs.major_minor}} --app-version ${{needs.read-version.outputs.major_minor}}
|
|
echo "OneUptime Helm Chart Package created successfully"
|
|
helm lint kubernetes-agent
|
|
helm template kubernetes-agent --values kubernetes-agent/values.yaml
|
|
helm package --sign --key 'key@oneuptime.com' --keyring ~/.gnupg/secring.gpg kubernetes-agent --version ${{needs.read-version.outputs.major_minor}} --app-version ${{needs.read-version.outputs.major_minor}}
|
|
echo "Kubernetes Agent Helm Chart Package created successfully"
|
|
cd ..
|
|
ls
|
|
echo "Copying the package to helm-chart repo"
|
|
rm -rf ../../helm-chart/oneuptime
|
|
rm -rf ../../helm-chart/kubernetes-agent
|
|
cp -r ./Public/* ../../helm-chart
|
|
echo "Package copied successfully"
|
|
cd .. && cd .. && cd helm-chart
|
|
echo "Updating helm-chart repo"
|
|
git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}"
|
|
git config --global user.email "hello@oneuptime.com"
|
|
echo "Git config set successfully"
|
|
echo "Adding the package to helm-chart repo"
|
|
helm repo index .
|
|
git add -A
|
|
git commit -m "Helm Chart Release ${{needs.read-version.outputs.major_minor}}"
|
|
git push origin master
|
|
|
|
# ─── Docker image build jobs (per-arch matrix) ───────────────────────
|
|
|
|
nginx-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image nginx \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./Nginx/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
nginx-docker-image-merge:
|
|
needs: [nginx-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image nginx \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
e2e-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image e2e \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./E2E/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
e2e-docker-image-merge:
|
|
needs: [e2e-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image e2e \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
home-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image home \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./Home/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
home-docker-image-merge:
|
|
needs: [home-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image home \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
test-server-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image test-server \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./TestServer/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
test-server-docker-image-merge:
|
|
needs: [test-server-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image test-server \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
test-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image test \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./Tests/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
test-docker-image-merge:
|
|
needs: [test-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image test \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
probe-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image probe \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./Probe/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
probe-docker-image-merge:
|
|
needs: [probe-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image probe \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
app-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image app \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./App/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
app-docker-image-merge:
|
|
needs: [app-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image app \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
ai-agent-docker-image-build:
|
|
needs: [generate-build-number, read-version]
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- platform: linux/amd64
|
|
runner: ubuntu-latest
|
|
- platform: linux/arm64
|
|
runner: ubuntu-24.04-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
if: matrix.platform == 'linux/amd64'
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Generate Dockerfile from Dockerfile.tpl
|
|
run: npm run prerun
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Build and push
|
|
run: |
|
|
bash ./Scripts/GHA/build_docker_images.sh \
|
|
--image ai-agent \
|
|
--version "${{needs.read-version.outputs.major_minor}}" \
|
|
--dockerfile ./AIAgent/Dockerfile \
|
|
--context . \
|
|
--platforms ${{ matrix.platform }} \
|
|
--git-sha "${{ github.sha }}"
|
|
|
|
ai-agent-docker-image-merge:
|
|
needs: [ai-agent-docker-image-build, read-version]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Merge multi-arch manifests
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
bash ./Scripts/GHA/merge_docker_manifests.sh \
|
|
--image ai-agent \
|
|
--tags "${SANITIZED_VERSION},enterprise-${SANITIZED_VERSION}"
|
|
|
|
publish-npm-packages:
|
|
runs-on: ubuntu-latest
|
|
needs: [generate-build-number, read-version]
|
|
permissions:
|
|
contents: read
|
|
id-token: write # Required for npm OIDC trusted publishing
|
|
env:
|
|
CI_PIPELINE_ID: ${{github.run_number}}
|
|
PACKAGE_VERSION: ${{needs.read-version.outputs.major_minor}}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
registry-url: 'https://registry.npmjs.org'
|
|
- name: Update npm for OIDC support
|
|
run: npm install -g npm@latest
|
|
- name: Preinstall
|
|
run: npm run prerun
|
|
- name: Publish NPM Packages
|
|
run: bash ./Scripts/NPM/PublishAllPackages.sh
|
|
|
|
# ─── Non-Docker jobs (downstream dependencies updated) ───────────────
|
|
|
|
publish-terraform-provider:
|
|
runs-on: ubuntu-latest
|
|
needs: [generate-build-number, read-version]
|
|
env:
|
|
CI_PIPELINE_ID: ${{github.run_number}}
|
|
GITHUB_TOKEN: ${{ secrets.SIMLARSEN_GITHUB_PAT }}
|
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
TERRAFORM_PROVIDER_GITHUB_REPO_DEPLOY_KEY: ${{ secrets.TERRAFORM_PROVIDER_GITHUB_REPO_DEPLOY_KEY }}
|
|
permissions:
|
|
contents: write # For creating releases
|
|
packages: write # For publishing packages
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 'latest'
|
|
cache: 'npm'
|
|
|
|
- name: Setup Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version: 'stable'
|
|
cache: true
|
|
|
|
- name: Install GoReleaser
|
|
uses: goreleaser/goreleaser-action@v5
|
|
with:
|
|
install-only: true
|
|
|
|
- name: Determine version
|
|
id: version
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Publishing Terraform provider version: $VERSION"
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
npm install
|
|
if [ -d "Common" ]; then cd Common && npm install && cd ..; fi
|
|
if [ -d "Scripts" ]; then cd Scripts && npm install && cd ..; fi
|
|
|
|
- name: Import GPG key
|
|
run: |
|
|
echo '${{ secrets.GPG_PRIVATE_KEY }}' > private.key
|
|
gpg --import private.key || true
|
|
rm private.key
|
|
echo "GPG key imported successfully"
|
|
gpg --export-secret-keys >~/.gnupg/secring.gpg
|
|
echo "GPG key exported successfully"
|
|
|
|
- name: Generate and publish Terraform provider
|
|
run: npm run publish-terraform-provider -- --version "${{ steps.version.outputs.version }}" --github-token "${{ secrets.SIMLARSEN_GITHUB_PAT }}" --github-repo-deploy-key "${{ secrets.TERRAFORM_PROVIDER_GITHUB_REPO_DEPLOY_KEY }}"
|
|
|
|
|
|
|
|
push-release-tags:
|
|
name: Push release tags before GitHub release
|
|
needs:
|
|
- read-version
|
|
- generate-build-number
|
|
- nginx-docker-image-merge
|
|
- e2e-docker-image-merge
|
|
- home-docker-image-merge
|
|
- test-server-docker-image-merge
|
|
- test-docker-image-merge
|
|
- probe-docker-image-merge
|
|
- app-docker-image-merge
|
|
- ai-agent-docker-image-merge
|
|
- test-e2e-release-saas
|
|
- test-e2e-release-self-hosted
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
image: [
|
|
"nginx",
|
|
"e2e",
|
|
"home",
|
|
"test-server",
|
|
"test",
|
|
"probe",
|
|
"app",
|
|
"ai-agent"
|
|
]
|
|
steps:
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Login to Docker Hub
|
|
run: |
|
|
echo "${{ secrets.DOCKERHUB_PASSWORD }}" | docker login --username "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
|
|
|
- name: Login to GitHub Container Registry
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.repository_owner }}" --password-stdin
|
|
|
|
- name: Create Docker Hub release tag from version
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
docker buildx imagetools create \
|
|
--tag oneuptime/${{ matrix.image }}:release \
|
|
ghcr.io/oneuptime/${{ matrix.image }}:${VERSION}
|
|
|
|
- name: Create GHCR release tag from version
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
docker buildx imagetools create \
|
|
--tag ghcr.io/oneuptime/${{ matrix.image }}:release \
|
|
ghcr.io/oneuptime/${{ matrix.image }}:${VERSION}
|
|
|
|
- name: Create Docker Hub enterprise release tag from version
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
docker buildx imagetools create \
|
|
--tag oneuptime/${{ matrix.image }}:enterprise-release \
|
|
ghcr.io/oneuptime/${{ matrix.image }}:enterprise-${VERSION}
|
|
|
|
- name: Create GHCR enterprise release tag from version
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
docker buildx imagetools create \
|
|
--tag ghcr.io/oneuptime/${{ matrix.image }}:enterprise-release \
|
|
ghcr.io/oneuptime/${{ matrix.image }}:enterprise-${VERSION}
|
|
|
|
|
|
|
|
test-e2e-release-saas:
|
|
runs-on: ubuntu-latest
|
|
needs: [ai-agent-docker-image-merge, app-docker-image-merge, home-docker-image-merge, probe-docker-image-merge, test-docker-image-merge, test-server-docker-image-merge, publish-npm-packages, e2e-docker-image-merge, helm-chart-deploy, generate-build-number, read-version, nginx-docker-image-merge]
|
|
env:
|
|
CI_PIPELINE_ID: ${{github.run_number}}
|
|
steps:
|
|
# Aggressively free disk space before anything else
|
|
- name: Aggressive Disk Cleanup
|
|
run: |
|
|
echo "=== Disk space BEFORE cleanup ==="
|
|
df -h /
|
|
# Remove pre-installed software not needed for this job
|
|
sudo rm -rf /usr/share/dotnet || true
|
|
sudo rm -rf /usr/local/lib/android || true
|
|
sudo rm -rf /opt/ghc || true
|
|
sudo rm -rf /opt/hostedtoolcache || true
|
|
sudo rm -rf /usr/local/share/boost || true
|
|
sudo rm -rf /usr/local/graalvm/ || true
|
|
sudo rm -rf /usr/local/share/powershell || true
|
|
sudo rm -rf /usr/local/share/chromium || true
|
|
sudo rm -rf /usr/local/lib/node_modules || true
|
|
sudo rm -rf /usr/share/swift || true
|
|
sudo rm -rf /usr/share/miniconda || true
|
|
sudo rm -rf /usr/lib/google-cloud-sdk || true
|
|
sudo rm -rf /usr/lib/jvm || true
|
|
sudo rm -rf /usr/lib/firefox || true
|
|
sudo rm -rf /usr/lib/heroku || true
|
|
sudo rm -rf /usr/local/julia* || true
|
|
sudo rm -rf /opt/az || true
|
|
sudo rm -rf /opt/microsoft || true
|
|
sudo rm -rf /opt/pipx || true
|
|
sudo rm -rf /opt/actionarchivecache || true
|
|
sudo rm -rf /imagegeneration || true
|
|
sudo rm -rf /usr/share/az_* || true
|
|
sudo rm -rf /usr/share/sbt || true
|
|
sudo rm -rf /usr/share/gradle* || true
|
|
sudo rm -rf /usr/share/kotlinc || true
|
|
sudo rm -rf /usr/share/ri || true
|
|
sudo rm -rf /usr/local/.ghcup || true
|
|
# Clean apt cache
|
|
sudo apt-get clean || true
|
|
sudo rm -rf /var/lib/apt/lists/* || true
|
|
# Clean temp files
|
|
sudo rm -rf /tmp/* || true
|
|
# Docker cleanup
|
|
docker system prune -af --volumes || true
|
|
echo "=== Disk space AFTER aggressive cleanup ==="
|
|
df -h /
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: true
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
- name: Final Disk Space Check
|
|
run: |
|
|
echo "=== Disk space after all cleanup ==="
|
|
df -h /
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
- name: Preinstall and enable billing
|
|
run: |
|
|
set -euo pipefail
|
|
npm run prerun
|
|
bash ./Tests/Scripts/enable-billing-env-var.sh
|
|
- name: Pin APP_TAG to versioned release
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
if [ -f config.env ]; then
|
|
if grep -q '^APP_TAG=' config.env; then
|
|
sed -i "s/^APP_TAG=.*/APP_TAG=${SANITIZED_VERSION}/" config.env
|
|
else
|
|
echo "APP_TAG=${SANITIZED_VERSION}" >> config.env
|
|
fi
|
|
else
|
|
echo "APP_TAG=${SANITIZED_VERSION}" > config.env
|
|
fi
|
|
- name: Start Server with version tag
|
|
run: |
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
docker compose -f docker-compose.billing.yml up --remove-orphans -d
|
|
npm run status-check
|
|
- name: Wait for server to start
|
|
run: bash ./Tests/Scripts/status-check.sh http://localhost
|
|
- name: Pull E2E test image
|
|
run: |
|
|
set -euo pipefail
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
docker compose -f docker-compose.e2e.yml pull e2e
|
|
- name: Run E2E Tests. Run docker container e2e in docker compose file
|
|
run: |
|
|
set -euo pipefail
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
trap 'docker compose -f docker-compose.e2e.yml down -v || true' EXIT
|
|
if ! docker compose -f docker-compose.e2e.yml up --exit-code-from e2e --abort-on-container-exit e2e; then
|
|
docker compose -f docker-compose.e2e.yml logs e2e
|
|
exit 1
|
|
fi
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@v4
|
|
# Run this on failure
|
|
if: failure()
|
|
with:
|
|
# Name of the artifact to upload.
|
|
# Optional. Default is 'artifact'
|
|
name: test-results-${{ github.job }}-${{ github.run_attempt }}
|
|
|
|
# A file, directory or wildcard pattern that describes what to upload
|
|
# Required.
|
|
path: |
|
|
./E2E
|
|
|
|
|
|
# Duration after which artifact will expire in days. 0 means using default retention.
|
|
# Minimum 1 day.
|
|
# Maximum 90 days unless changed from the repository settings page.
|
|
# Optional. Defaults to repository settings.
|
|
retention-days: 7
|
|
|
|
|
|
test-e2e-release-self-hosted:
|
|
runs-on: ubuntu-latest
|
|
# After all the jobs runs
|
|
needs: [ai-agent-docker-image-merge, app-docker-image-merge, home-docker-image-merge, probe-docker-image-merge, test-docker-image-merge, test-server-docker-image-merge, publish-npm-packages, e2e-docker-image-merge, helm-chart-deploy, generate-build-number, read-version, nginx-docker-image-merge]
|
|
env:
|
|
CI_PIPELINE_ID: ${{github.run_number}}
|
|
steps:
|
|
# Aggressively free disk space before anything else
|
|
- name: Aggressive Disk Cleanup
|
|
run: |
|
|
echo "=== Disk space BEFORE cleanup ==="
|
|
df -h /
|
|
# Remove pre-installed software not needed for this job
|
|
sudo rm -rf /usr/share/dotnet || true
|
|
sudo rm -rf /usr/local/lib/android || true
|
|
sudo rm -rf /opt/ghc || true
|
|
sudo rm -rf /opt/hostedtoolcache || true
|
|
sudo rm -rf /usr/local/share/boost || true
|
|
sudo rm -rf /usr/local/graalvm/ || true
|
|
sudo rm -rf /usr/local/share/powershell || true
|
|
sudo rm -rf /usr/local/share/chromium || true
|
|
sudo rm -rf /usr/local/lib/node_modules || true
|
|
sudo rm -rf /usr/share/swift || true
|
|
sudo rm -rf /usr/share/miniconda || true
|
|
sudo rm -rf /usr/lib/google-cloud-sdk || true
|
|
sudo rm -rf /usr/lib/jvm || true
|
|
sudo rm -rf /usr/lib/firefox || true
|
|
sudo rm -rf /usr/lib/heroku || true
|
|
sudo rm -rf /usr/local/julia* || true
|
|
sudo rm -rf /opt/az || true
|
|
sudo rm -rf /opt/microsoft || true
|
|
sudo rm -rf /opt/pipx || true
|
|
sudo rm -rf /opt/actionarchivecache || true
|
|
sudo rm -rf /imagegeneration || true
|
|
sudo rm -rf /usr/share/az_* || true
|
|
sudo rm -rf /usr/share/sbt || true
|
|
sudo rm -rf /usr/share/gradle* || true
|
|
sudo rm -rf /usr/share/kotlinc || true
|
|
sudo rm -rf /usr/share/ri || true
|
|
sudo rm -rf /usr/local/.ghcup || true
|
|
# Clean apt cache
|
|
sudo apt-get clean || true
|
|
sudo rm -rf /var/lib/apt/lists/* || true
|
|
# Clean temp files
|
|
sudo rm -rf /tmp/* || true
|
|
# Docker cleanup
|
|
docker system prune -af --volumes || true
|
|
echo "=== Disk space AFTER aggressive cleanup ==="
|
|
df -h /
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: true
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
- name: Final Disk Space Check
|
|
run: |
|
|
echo "=== Disk space after all cleanup ==="
|
|
df -h /
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
- name: Preinstall
|
|
run: |
|
|
set -euo pipefail
|
|
npm run prerun
|
|
- name: Pin APP_TAG to versioned release
|
|
run: |
|
|
VERSION="${{needs.read-version.outputs.major_minor}}"
|
|
SANITIZED_VERSION="${VERSION//+/-}"
|
|
if [ -f config.env ]; then
|
|
if grep -q '^APP_TAG=' config.env; then
|
|
sed -i "s/^APP_TAG=.*/APP_TAG=${SANITIZED_VERSION}/" config.env
|
|
else
|
|
echo "APP_TAG=${SANITIZED_VERSION}" >> config.env
|
|
fi
|
|
else
|
|
echo "APP_TAG=${SANITIZED_VERSION}" > config.env
|
|
fi
|
|
- name: Start Server with version tag
|
|
run: |
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
docker compose up --remove-orphans -d
|
|
npm run status-check
|
|
- name: Wait for server to start
|
|
run: bash ./Tests/Scripts/status-check.sh http://localhost
|
|
- name: Pull E2E test image
|
|
run: |
|
|
set -euo pipefail
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
docker compose -f docker-compose.e2e.yml pull e2e
|
|
- name: Run E2E Tests. Run docker container e2e in docker compose file
|
|
run: |
|
|
set -euo pipefail
|
|
export $(grep -v '^#' config.env | xargs)
|
|
export APP_TAG=${{needs.read-version.outputs.major_minor}}
|
|
trap 'docker compose -f docker-compose.e2e.yml down -v || true' EXIT
|
|
if ! docker compose -f docker-compose.e2e.yml up --exit-code-from e2e --abort-on-container-exit e2e; then
|
|
docker compose -f docker-compose.e2e.yml logs e2e
|
|
exit 1
|
|
fi
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@v4
|
|
# Run this on failure
|
|
if: failure()
|
|
with:
|
|
# Name of the artifact to upload.
|
|
# Optional. Default is 'artifact'
|
|
name: test-results-${{ github.job }}-${{ github.run_attempt }}
|
|
|
|
# A file, directory or wildcard pattern that describes what to upload
|
|
# Required.
|
|
path: |
|
|
./E2E
|
|
|
|
|
|
# Duration after which artifact will expire in days. 0 means using default retention.
|
|
# Minimum 1 day.
|
|
# Maximum 90 days unless changed from the repository settings page.
|
|
# Optional. Defaults to repository settings.
|
|
retention-days: 7
|
|
|
|
draft-github-release:
|
|
name: Create draft GitHub release
|
|
needs: [test-e2e-release-saas, test-e2e-release-self-hosted, generate-build-number, read-version, push-release-tags]
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/release'
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
- run: echo "${{needs.generate-build-number.outputs.build_number}}"
|
|
- name: "Build Changelog"
|
|
id: build_changelog
|
|
uses: mikepenz/release-changelog-builder-action@v4.2.0
|
|
with:
|
|
configuration: "./Scripts/Release/ChangelogConfig.json"
|
|
- run: echo "Changelog:"
|
|
- run: echo "${{steps.build_changelog.outputs.changelog}}"
|
|
- name: Fallback to commit messages if changelog empty
|
|
id: fallback_changelog
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
CHANGELOG_CONTENT="${{steps.build_changelog.outputs.changelog}}"
|
|
OLD_PLACEHOLDER="No significant changes were made. We have just fixed minor bugs for this release. You can find the detailed information in the commit history."
|
|
NEW_PLACEHOLDER="(auto) No categorized pull requests. Fallback will list raw commit messages."
|
|
if echo "$CHANGELOG_CONTENT" | grep -Fq "$OLD_PLACEHOLDER" || echo "$CHANGELOG_CONTENT" | grep -Fq "$NEW_PLACEHOLDER"; then
|
|
echo "Detected empty placeholder changelog. Building commit list fallback."
|
|
# Find previous tag (skip the most recent tag which might be for an older release). If none, include all commits.
|
|
if prev_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --skip=1 --max-count=1) 2>/dev/null); then
|
|
echo "Previous tag: $prev_tag"
|
|
commits=$(git log --pretty=format:'- %s (%h)' "$prev_tag"..HEAD)
|
|
else
|
|
echo "No previous tag found; using full commit history on this branch."
|
|
commits=$(git log --pretty=format:'- %s (%h)')
|
|
fi
|
|
# If still empty (e.g., no commits), keep placeholder to avoid empty body.
|
|
if [ -z "$commits" ]; then
|
|
commits="(no commits found)"
|
|
fi
|
|
{
|
|
echo "changelog<<EOF"
|
|
echo "## Commit Messages"
|
|
echo ""
|
|
echo "$commits"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
else
|
|
# Pass through original changelog
|
|
{
|
|
echo "changelog<<EOF"
|
|
echo "$CHANGELOG_CONTENT"
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
fi
|
|
- uses: ncipollo/release-action@v1
|
|
with:
|
|
tag: "${{needs.read-version.outputs.major_minor}}"
|
|
artifactErrorsFailBuild: true
|
|
draft: true
|
|
allowUpdates: true
|
|
prerelease: false
|
|
body: |
|
|
${{steps.fallback_changelog.outputs.changelog}}
|
|
|
|
infrastructure-agent-deploy:
|
|
needs: [draft-github-release, generate-build-number, read-version]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: true
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: true
|
|
swap-storage: true
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v4
|
|
|
|
- name: Install GoReleaser
|
|
uses: goreleaser/goreleaser-action@v6.1.0
|
|
with:
|
|
install-only: true
|
|
|
|
- name: GoReleaser Version
|
|
run: goreleaser -v
|
|
|
|
# This tool is used to generate .rpm and .deb packages
|
|
- name: Install NFPM
|
|
run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
|
|
|
|
- name: Show GoReleaser version
|
|
run: goreleaser -v
|
|
|
|
- name: Run GoReleaser
|
|
run: cd InfrastructureAgent && export GORELEASER_CURRENT_TAG=${{needs.read-version.outputs.major_minor}} && goreleaser release --clean --snapshot
|
|
|
|
- name: Release MSI Images
|
|
run: cd InfrastructureAgent && bash build-msi.sh ${{needs.read-version.outputs.major_minor}}
|
|
|
|
# Upload binaries to github release
|
|
- name: Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
files: |
|
|
InfrastructureAgent/dist/*
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
draft: true
|
|
prerelease: false
|
|
tag_name: ${{needs.read-version.outputs.major_minor}}
|
|
|
|
|
|
# Build Android release APK and attach to GitHub Release.
|
|
# Required secrets setup guide: MobileApp/docs/RELEASE_SIGNING.md
|
|
mobile-app-android-deploy:
|
|
needs: [draft-github-release, generate-build-number, read-version]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Setup Java 17
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: '17'
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Install dependencies
|
|
run: cd MobileApp && npm install
|
|
|
|
- name: Generate native Android project
|
|
run: cd MobileApp && npx expo prebuild --platform android --no-install
|
|
|
|
- name: Decode Android keystore
|
|
run: |
|
|
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > /tmp/release.keystore
|
|
|
|
- name: Build release APK
|
|
env:
|
|
ANDROID_KEYSTORE_FILE: /tmp/release.keystore
|
|
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
run: |
|
|
cd MobileApp/android
|
|
./gradlew assembleRelease \
|
|
-PversionName=${{ needs.read-version.outputs.major_minor }} \
|
|
-PversionCode=${{ needs.generate-build-number.outputs.build_number }}
|
|
|
|
- name: Rename APK
|
|
run: mv MobileApp/android/app/build/outputs/apk/release/*.apk MobileApp/android/app/build/outputs/apk/release/oneuptime-on-call-android-app.apk
|
|
|
|
- name: Upload APK to GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
files: MobileApp/android/app/build/outputs/apk/release/oneuptime-on-call-android-app.apk
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
draft: true
|
|
prerelease: false
|
|
tag_name: ${{ needs.read-version.outputs.major_minor }}
|
|
|
|
# Build iOS release IPA and attach to GitHub Release.
|
|
# Required secrets setup guide: MobileApp/docs/RELEASE_SIGNING.md
|
|
mobile-app-ios-deploy:
|
|
needs: [draft-github-release, generate-build-number, read-version]
|
|
runs-on: macos-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Install dependencies
|
|
run: cd MobileApp && npm install
|
|
|
|
- name: Generate native iOS project
|
|
run: cd MobileApp && npx expo prebuild --platform ios --no-install
|
|
|
|
- name: Install CocoaPods dependencies
|
|
run: cd MobileApp/ios && pod install
|
|
|
|
- name: Import signing certificate
|
|
env:
|
|
IOS_DISTRIBUTION_CERTIFICATE_BASE64: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_BASE64 }}
|
|
IOS_DISTRIBUTION_CERTIFICATE_PASSWORD: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_PASSWORD }}
|
|
run: |
|
|
CERTIFICATE_PATH=$RUNNER_TEMP/distribution.p12
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
|
|
|
echo "$IOS_DISTRIBUTION_CERTIFICATE_BASE64" | base64 --decode > "$CERTIFICATE_PATH"
|
|
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
|
|
security import "$CERTIFICATE_PATH" -P "$IOS_DISTRIBUTION_CERTIFICATE_PASSWORD" \
|
|
-A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
|
|
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
security list-keychain -d user -s "$KEYCHAIN_PATH"
|
|
|
|
- name: Install provisioning profile
|
|
env:
|
|
IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
|
|
run: |
|
|
PROFILE_PATH=$RUNNER_TEMP/profile.mobileprovision
|
|
echo "$IOS_PROVISIONING_PROFILE_BASE64" | base64 --decode > "$PROFILE_PATH"
|
|
|
|
# Extract the UUID from the profile and install with UUID as filename
|
|
# This is required for Xcode to find the profile during manual code signing
|
|
PROFILE_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(/usr/bin/security cms -D -i "$PROFILE_PATH"))
|
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
|
cp "$PROFILE_PATH" ~/Library/MobileDevice/Provisioning\ Profiles/"$PROFILE_UUID".mobileprovision
|
|
|
|
echo "PROFILE_UUID=$PROFILE_UUID" >> $GITHUB_ENV
|
|
|
|
- name: Build archive
|
|
env:
|
|
IOS_TEAM_ID: ${{ secrets.IOS_TEAM_ID }}
|
|
run: |
|
|
if [ -z "$IOS_TEAM_ID" ]; then
|
|
echo "::error::IOS_TEAM_ID secret is not set"
|
|
exit 1
|
|
fi
|
|
cd MobileApp
|
|
xcodebuild -workspace ios/OneUptimeOnCall.xcworkspace \
|
|
-scheme OneUptimeOnCall \
|
|
-configuration Release \
|
|
-sdk iphoneos \
|
|
-archivePath $RUNNER_TEMP/OneUptimeOnCall.xcarchive \
|
|
archive \
|
|
CODE_SIGN_STYLE=Manual \
|
|
CODE_SIGN_IDENTITY="iPhone Distribution" \
|
|
DEVELOPMENT_TEAM="$IOS_TEAM_ID" \
|
|
PROVISIONING_PROFILE="${{ env.PROFILE_UUID }}" \
|
|
MARKETING_VERSION=${{ needs.read-version.outputs.major_minor }} \
|
|
CURRENT_PROJECT_VERSION=${{ needs.generate-build-number.outputs.build_number }}
|
|
|
|
- name: Prepare ExportOptions.plist with team ID
|
|
env:
|
|
IOS_TEAM_ID: ${{ secrets.IOS_TEAM_ID }}
|
|
run: |
|
|
/usr/libexec/PlistBuddy -c "Add :teamID string $IOS_TEAM_ID" MobileApp/ios/ExportOptions.plist || \
|
|
/usr/libexec/PlistBuddy -c "Set :teamID $IOS_TEAM_ID" MobileApp/ios/ExportOptions.plist
|
|
|
|
- name: Export IPA
|
|
run: |
|
|
cd MobileApp
|
|
xcodebuild -exportArchive \
|
|
-archivePath $RUNNER_TEMP/OneUptimeOnCall.xcarchive \
|
|
-exportOptionsPlist ios/ExportOptions.plist \
|
|
-exportPath $RUNNER_TEMP/build
|
|
|
|
- name: Rename IPA
|
|
run: mv ${{ runner.temp }}/build/*.ipa ${{ runner.temp }}/build/oneuptime-on-call-ios-app.ipa
|
|
|
|
- name: Upload IPA to GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
files: ${{ runner.temp }}/build/oneuptime-on-call-ios-app.ipa
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
draft: true
|
|
prerelease: false
|
|
tag_name: ${{ needs.read-version.outputs.major_minor }}
|
|
|
|
- name: Cleanup keychain
|
|
if: always()
|
|
run: |
|
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
|
|
|
|
finalize-github-release:
|
|
name: Publish GitHub release
|
|
needs: [infrastructure-agent-deploy, generate-build-number, read-version]
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/release'
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Publish release
|
|
uses: actions/github-script@v7
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
const tag = '${{needs.read-version.outputs.major_minor}}';
|
|
try {
|
|
const releases = await github.paginate(github.rest.repos.listReleases, {
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
per_page: 100,
|
|
});
|
|
|
|
const release = releases.find((item) => item.tag_name === tag);
|
|
|
|
if (!release) {
|
|
throw new Error(`Release with tag ${tag} not found in repository ${context.repo.owner}/${context.repo.repo}`);
|
|
}
|
|
|
|
await github.rest.repos.updateRelease({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
release_id: release.id,
|
|
draft: false,
|
|
prerelease: false,
|
|
make_latest: 'true',
|
|
});
|
|
|
|
console.log(`Published release for ${tag}`);
|
|
} catch (error) {
|
|
throw new Error(`Failed to publish release for tag ${tag}: ${error.message ?? error}`);
|
|
}
|
|
|
|
# Publish Android app to Google Play Store.
|
|
# This job only runs when manually triggered via workflow_dispatch with publish_android_to_store=true.
|
|
# Required secrets:
|
|
# - GOOGLE_PLAY_SERVICE_ACCOUNT_JSON: Service account JSON key with Play Store publishing access
|
|
# - ANDROID_KEYSTORE_BASE64: Base64-encoded release keystore
|
|
# - ANDROID_KEYSTORE_PASSWORD: Keystore password
|
|
# - ANDROID_KEY_ALIAS: Signing key alias
|
|
# - ANDROID_KEY_PASSWORD: Signing key password
|
|
publish-android-to-play-store:
|
|
needs: [generate-build-number, read-version]
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish_android_to_store == 'true'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- name: Setup Java 17
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: 'temurin'
|
|
java-version: '17'
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Install dependencies
|
|
run: cd MobileApp && npm install
|
|
|
|
- name: Generate native Android project
|
|
run: cd MobileApp && npx expo prebuild --platform android --no-install
|
|
|
|
- name: Decode Android keystore
|
|
run: |
|
|
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > /tmp/release.keystore
|
|
|
|
- name: Build release AAB for Play Store
|
|
env:
|
|
ANDROID_KEYSTORE_FILE: /tmp/release.keystore
|
|
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
run: |
|
|
cd MobileApp/android
|
|
./gradlew bundleRelease \
|
|
-PversionName=${{ needs.read-version.outputs.major_minor }} \
|
|
-PversionCode=${{ needs.generate-build-number.outputs.build_number }}
|
|
|
|
- name: Upload AAB as build artifact
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: android-aab-${{ needs.read-version.outputs.major_minor }}
|
|
path: MobileApp/android/app/build/outputs/bundle/release/*.aab
|
|
retention-days: 90
|
|
|
|
- name: Upload AAB to Google Play Store
|
|
uses: r0adkll/upload-google-play@v1
|
|
with:
|
|
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
|
|
packageName: com.oneuptime.oncall
|
|
releaseFiles: MobileApp/android/app/build/outputs/bundle/release/*.aab
|
|
track: production
|
|
status: completed
|
|
|
|
|
|
# Publish iOS app to App Store.
|
|
# This job only runs when manually triggered via workflow_dispatch with publish_ios_to_store=true.
|
|
# Required secrets:
|
|
# - IOS_DISTRIBUTION_CERTIFICATE_BASE64: Base64-encoded P12 distribution certificate
|
|
# - IOS_DISTRIBUTION_CERTIFICATE_PASSWORD: Password for the P12 certificate
|
|
# - IOS_PROVISIONING_PROFILE_BASE64: Base64-encoded App Store distribution provisioning profile
|
|
# - APP_STORE_CONNECT_API_KEY_ID: App Store Connect API key ID
|
|
# - APP_STORE_CONNECT_API_ISSUER_ID: App Store Connect API issuer ID
|
|
# - APP_STORE_CONNECT_API_KEY_BASE64: Base64-encoded App Store Connect API private key (.p8)
|
|
publish-ios-to-app-store:
|
|
needs: [generate-build-number, read-version]
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish_ios_to_store == 'true'
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: latest
|
|
|
|
- name: Install dependencies
|
|
run: cd MobileApp && npm install
|
|
|
|
- name: Generate native iOS project
|
|
run: cd MobileApp && npx expo prebuild --platform ios --no-install
|
|
|
|
- name: Install CocoaPods dependencies
|
|
run: cd MobileApp/ios && pod install
|
|
|
|
- name: Setup Apple signing certificate and provisioning profile
|
|
env:
|
|
IOS_DISTRIBUTION_CERTIFICATE_BASE64: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_BASE64 }}
|
|
IOS_DISTRIBUTION_CERTIFICATE_PASSWORD: ${{ secrets.IOS_DISTRIBUTION_CERTIFICATE_PASSWORD }}
|
|
IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
|
|
run: |
|
|
# Create a temporary keychain
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
|
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
|
|
# Import distribution certificate
|
|
CERTIFICATE_PATH=$RUNNER_TEMP/distribution_certificate.p12
|
|
echo "$IOS_DISTRIBUTION_CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH
|
|
security import $CERTIFICATE_PATH -P "$IOS_DISTRIBUTION_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
|
|
# Install provisioning profile
|
|
PROFILE_PATH=$RUNNER_TEMP/distribution_profile.mobileprovision
|
|
echo "$IOS_PROVISIONING_PROFILE_BASE64" | base64 --decode > $PROFILE_PATH
|
|
|
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
|
PROFILE_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(/usr/bin/security cms -D -i $PROFILE_PATH))
|
|
cp $PROFILE_PATH ~/Library/MobileDevice/Provisioning\ Profiles/$PROFILE_UUID.mobileprovision
|
|
|
|
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV
|
|
echo "PROFILE_UUID=$PROFILE_UUID" >> $GITHUB_ENV
|
|
|
|
- name: Build iOS archive
|
|
run: |
|
|
cd MobileApp/ios
|
|
xcodebuild archive \
|
|
-workspace OneUptimeOnCall.xcworkspace \
|
|
-scheme OneUptimeOnCall \
|
|
-configuration Release \
|
|
-archivePath $RUNNER_TEMP/OneUptimeOnCall.xcarchive \
|
|
-destination 'generic/platform=iOS' \
|
|
MARKETING_VERSION=${{ needs.read-version.outputs.major_minor }} \
|
|
CURRENT_PROJECT_VERSION=${{ needs.generate-build-number.outputs.build_number }} \
|
|
CODE_SIGN_STYLE=Manual \
|
|
CODE_SIGN_IDENTITY="Apple Distribution" \
|
|
PROVISIONING_PROFILE_SPECIFIER="${{ env.PROFILE_UUID }}" \
|
|
OTHER_CODE_SIGN_FLAGS="--keychain ${{ env.KEYCHAIN_PATH }}"
|
|
|
|
- name: Export IPA
|
|
run: |
|
|
# Create export options plist
|
|
cat > $RUNNER_TEMP/ExportOptions.plist << EOF
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>method</key>
|
|
<string>app-store</string>
|
|
<key>destination</key>
|
|
<string>upload</string>
|
|
<key>signingStyle</key>
|
|
<string>manual</string>
|
|
<key>provisioningProfiles</key>
|
|
<dict>
|
|
<key>com.oneuptime.oncall</key>
|
|
<string>${{ env.PROFILE_UUID }}</string>
|
|
</dict>
|
|
<key>uploadSymbols</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
|
|
xcodebuild -exportArchive \
|
|
-archivePath $RUNNER_TEMP/OneUptimeOnCall.xcarchive \
|
|
-exportOptionsPlist $RUNNER_TEMP/ExportOptions.plist \
|
|
-exportPath $RUNNER_TEMP/ios-export
|
|
|
|
- name: Upload IPA as build artifact
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: ios-ipa-${{ needs.read-version.outputs.major_minor }}
|
|
path: ${{ runner.temp }}/ios-export/*.ipa
|
|
retention-days: 90
|
|
|
|
- name: Upload to App Store Connect
|
|
env:
|
|
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
|
|
APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }}
|
|
run: |
|
|
# Decode API key
|
|
API_KEY_PATH=$RUNNER_TEMP/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8
|
|
echo "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode > $API_KEY_PATH
|
|
|
|
xcrun notarytool store-credentials "appstore-credentials" \
|
|
--key $API_KEY_PATH \
|
|
--key-id $APP_STORE_CONNECT_API_KEY_ID \
|
|
--issuer $APP_STORE_CONNECT_API_ISSUER_ID 2>/dev/null || true
|
|
|
|
xcrun altool --upload-app \
|
|
--type ios \
|
|
--file $(find $RUNNER_TEMP/ios-export -name '*.ipa' -print -quit) \
|
|
--apiKey $APP_STORE_CONNECT_API_KEY_ID \
|
|
--apiIssuer $APP_STORE_CONNECT_API_ISSUER_ID
|
|
|
|
- name: Cleanup signing artifacts
|
|
if: always()
|
|
run: |
|
|
security delete-keychain ${{ env.KEYCHAIN_PATH }} 2>/dev/null || true
|
|
rm -f $RUNNER_TEMP/distribution_certificate.p12
|
|
rm -f $RUNNER_TEMP/distribution_profile.mobileprovision
|
|
rm -f $RUNNER_TEMP/AuthKey_*.p8
|