Skip to content
9 changes: 7 additions & 2 deletions .cursorrules → .cursor/rules/bash_scripts.mdc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
description: Standards and Rules to follow when editing bash scripts in @bin/
globs: bin/*
---
# Shell Script Documentation and Standards

## Shell Script Standards
Expand Down Expand Up @@ -37,10 +41,11 @@ For all bash shell scripts, avoid using:

## Documentation Requirements

When editing or creating files in `/bin`:
When editing or creating files:
- Every shell script must have comprehensive header documentation
- Documentation must include: description, usage, parameters, examples
- For complex logic, provide detailed examples of different use cases
- Use backticks (`) around command names, executables, and technical terms in documentation
- Document all return values and exit codes
- Keep documentation up to date with any changes

Expand Down Expand Up @@ -83,7 +88,7 @@ When editing or creating files in `/bin`:

- Use POSIX-compliant syntax and commands
- Ensure the script is at least compatible with macOS and Linux
- Make your best effort to make the bash scripts also compatible with Windows if possible, in addition to macOS and Linux. If it's not possible, document that in the script's header documentation
- Make your best effort to make the bash scripts also compatible with Windows if possible, in addition to macOS and Linux. If it's not possible, document that in the script's header documentation, and, if the features handled by the bash script would be useful and make sense for use cases where we'd still need a Windows agent, propose your help to the author of the original script to create a PowerShell counterpart of that script to provide the same functionality for when running on Windows agents.
- If the script would behave differently on different platforms despite your best efforts to make it behave the same way cross-platform, document any such platform-specific behavior in the script header documentation

### For bash scripts compatible with macOS and Linux
Expand Down
11 changes: 11 additions & 0 deletions .cursor/rules/context.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
description: Provide context to the agent about this repository and how its files are used
globs:
---
# Context

- You are a senior software engineer working at Automattic, and you are part of the Apps Infra team, responsible for our CI infrastructure, including providing tools and scripts to run on our CI agents.
- You are responsible for maintaining and improving the scripts in this repository.
- Our CI runs on Buildkite infrastructure, using a mix of self-hosted agents (MacMinis in our DataCenter) and Linux or Windows EC2 instances on AWS.
- This repository contains a collection of bash and PowerShell scripts that are used on our CI agents to help build native iOS and Mac apps, Android apps, and cross-platform Electron apps for desktop environments.
- Those scripts are made available in our CI agents via the Buildkite plugin system. The scripts in the `bin/` directory are available in the `$PATH` of all our CI jobs that use `a8c-ci-toolkit` in their pipeline steps' `plugins:` attribute.
141 changes: 141 additions & 0 deletions .cursor/rules/powershell_scripts.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
description: Standards and Rules to follow when editing PowerShell scripts in @bin/
globs: *.ps1
---
# PowerShell Script Documentation and Standards

## PowerShell Script Standards

For all PowerShell scripts:
- Ensure compatibility with Windows PowerShell 5.1 (default on Windows Server)
- Follow `PSScriptAnalyzer` recommendations
- Use proper error handling and input validation
- Use UTF-8 encoding without BOM for script files
- Document Windows-specific requirements and dependencies

## Best Practices

For all PowerShell scripts:
- Use `$ErrorActionPreference = "Stop"` at the beginning of scripts
- Use `Set-StrictMode -Version Latest` for strict variable and function checking
- Always use full cmdlet names (avoid aliases like `ls`, use `Get-ChildItem` instead)
- Use proper verb-noun naming convention for functions
- Quote all variable expansions in strings
- Use `[CmdletBinding()]` for advanced functions
- Use parameter validation attributes
- Include proper error handling with try/catch blocks
- Use approved PowerShell verbs (Get-Verb)
- End script files with a newline
- Use proper PowerShell case conventions:
- PascalCase for functions, cmdlets, and parameters
- camelCase for variables
- UPPERCASE for constants
- Check for and require Administrator privileges when needed using:

```powershell
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
throw "This script requires Administrator privileges"
}
```

## Documentation Requirements

When editing or creating PowerShell scripts in `/bin`:
- Every script must have comprehensive comment-based help
- Documentation must include: synopsis, description, parameters, examples
- For complex logic, provide detailed examples of different use cases
- Use backticks (`) around command names, executables, and technical terms in documentation
- Document all return values and terminating conditions
- Keep documentation up to date with any changes
- Clearly document Windows version requirements or limitations
- Document required Windows features or roles

## Documentation Template

```powershell
<#
.SYNOPSIS
Brief description of what the script does.

.DESCRIPTION
Detailed description of the script's purpose and functionality.

.PARAMETER ParameterName
Description of each parameter.

.EXAMPLE
Example-1
Detailed description of the example.

.NOTES
Author: [Author name]
Last Edit: [Date]
Version 1.0 - Initial release
Requirements: Windows PowerShell 5.1
Windows Requirements:
- Windows Server 2019 or later
- Required Windows Features: [list features]
- Required Windows Roles: [list roles]
- Administrator privileges: [Yes/No]

.OUTPUTS
Description of the script's output.

.RETURNVALUES
Description of possible return values and their meanings.
#>
```

## Windows-Specific Best Practices

### Registry Operations
- Always use try/catch blocks when modifying registry
- Use proper registry paths (HKLM:\ instead of HKEY_LOCAL_MACHINE)
- Check registry key existence before operations
- Document any registry modifications in script header

### Windows Services
- Use proper error handling for service operations
- Check service status before operations
- Handle service dependencies
- Document required service account privileges

### File System Operations
- Use proper path handling for Windows paths
- Handle long path limitations appropriately
- Use proper file system permissions checks
- Handle file locks and sharing violations

### Windows Features and Roles
- Document required Windows features
- Check feature presence before operations
- Handle feature installation failures
- Document minimum Windows version requirements

### Required PowerShell Modules

For any PowerShell script that needs additional modules:
- Document required modules in the script's help section
- Use `#Requires -Modules` statements at the start of the script
- Include minimum version requirements if specific versions are needed
- Document any Windows-specific module dependencies

## Script Validation

Before committing PowerShell scripts, ensure:
- PSScriptAnalyzer passes with no warnings
- Comment-based help is complete
- Windows requirements are documented
- All functions have proper error handling
- Variables are properly scoped
- Parameters are properly validated
- Administrator requirements are documented and checked if needed

## PowerShell Compatibility

For all PowerShell scripts, avoid using:
- PowerShell 7.x exclusive features
- Deprecated cmdlets and parameters
- Write-Host (use Write-Output or Write-Information instead)
- Positional parameters (always use named parameters)
- Global variables without explicit scope declaration
83 changes: 69 additions & 14 deletions bin/build_and_test_pod
Original file line number Diff line number Diff line change
@@ -1,27 +1,82 @@
#!/bin/bash -eu
#!/bin/bash

# Script: build_and_test_pod
#
# Description:
# Builds and tests a CocoaPods library using Fastlane. Handles both standard
# and Example project structures, installing dependencies as needed.
#
# Usage:
# build_and_test_pod [FASTLANE_ARGS...]
#
# Arguments:
# FASTLANE_ARGS - Arguments passed directly to fastlane (optional, defaults to 'test')
#
# Returns:
# 0 - Build and tests passed successfully
# 1 - Setup failed (gems, pods, etc.)
# 2 - Build or tests failed
#
# Any arguments passed to this script will be passed through to `fastlane`.
# If no argument is passed, the `test` lane will be called by default.
# Notes:
# - Must run on a macOS CI agent with Xcode installed
# - Supports both standard pod structure and Example project structure
# - Will install dependencies in both root and Example/ directory if needed
# - Uses Fastlane for build and test execution
#
# Requirements:
# This script needs to run on a CI agent which has the following external commands installed:
# - `bundle`
# - `fastlane` (via bundler)
# - `xcrun`
# - `install_gems` (provided by a8c-ci-toolkit)
# - `install_cocoapods` (provided by a8c-ci-toolkit)

set -euo pipefail

echo "--- :rubygems: Setting up Gems"
install_gems
if ! install_gems; then
echo "Error: Failed to install required gems" >&2
exit 1
fi

if [ -f "Podfile.lock" ]; then
echo "--- :cocoapods: Setting up Pods"
install_cocoapods
# Install pods in root directory if needed
if [[ -f "Podfile.lock" ]]; then
echo "--- :cocoapods: Setting up Pods"
if ! install_cocoapods; then
echo "Error: Failed to install pods in root directory" >&2
exit 1
fi
fi

if [ -f "Example/Podfile.lock" ]; then
cd Example
echo "--- :cocoapods: Setting up Pods"
install_cocoapods
cd -
# Install pods in Example directory if needed
if [[ -f "Example/Podfile.lock" ]]; then
echo "--- :cocoapods: Setting up Example Pods"
# Use pushd/popd for safer directory navigation
pushd Example > /dev/null || {
echo "Error: Failed to change to Example directory" >&2
exit 1
}

if ! install_cocoapods; then
echo "Error: Failed to install pods in Example directory" >&2
popd > /dev/null
exit 1
fi

popd > /dev/null
fi

echo "--- :test_tube: Building and Running Tests"

# For some reason this fixes a failure in `lib lint`
# https://github.com/Automattic/buildkite-ci/issues/7
xcrun simctl list >> /dev/null
if ! xcrun simctl list >> /dev/null; then
echo "Error: Failed to list simulators. Is Xcode properly installed?" >&2
exit 1
fi

bundle exec fastlane "${@:-test}"
# Run fastlane with provided arguments or 'test' by default
if ! bundle exec fastlane "${@:-test}"; then
echo "Error: Fastlane execution failed" >&2
exit 2
fi
25 changes: 23 additions & 2 deletions bin/cache_cocoapods
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
#!/bin/bash -eu
#!/bin/bash

# This file is deprecated, but is being kept around until v2.0
# Script: cache_cocoapods
#
# Description:
# [DEPRECATED] This script has been replaced by `cache_cocoapods_specs_repos`.
# It now only forwards to the new script for backward compatibility.
#
# Usage:
# cache_cocoapods
#
# Returns:
# - Returns the same exit code as `cache_cocoapods_specs_repos`
#
# Notes:
# - This script is deprecated and will be removed in v2.0
# - Users should migrate to using `cache_cocoapods_specs_repos` directly
# - This script exists only for backward compatibility
#
# Requirements:
# - `cache_cocoapods_specs_repos` (provided by a8c-ci-toolkit)

set -euo pipefail

# Forward to the new script
cache_cocoapods_specs_repos
43 changes: 39 additions & 4 deletions bin/cache_cocoapods_specs_repos
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
#!/bin/bash -eu
#!/bin/bash

# Script: cache_cocoapods_specs_repos
#
# Description:
# Updates and caches CocoaPods specs repositories and the global CocoaPods cache.
# This script handles both the global CocoaPods specs repo and the global CocoaPods cache directory.
#
# Usage:
# cache_cocoapods_specs_repos
#
# Notes:
# - This script must run on a macOS CI agent with CocoaPods installed
# - It expects the current directory to be the root of an iOS/macOS project
# - If a Podfile exists, it will run `pod install` and cache the global CocoaPods cache directory
#
# Returns:
# 0 - Cache was successfully updated and saved
# 1 - Required environment variable is missing or other error occurred
#
# Requirements:
# This script needs to run on a CI agent which has the following external commands installed:
# - `bundle`
# - `pod` (via bundler)
# - `save_cache` (provided by a8c-ci-toolkit)
#
# Environment Variables:
# BUILDKITE_PIPELINE_SLUG - The slug of the current buildkite pipeline (required)

set -euo pipefail

# Validate required environment variable
if [[ -z "${BUILDKITE_PIPELINE_SLUG:-}" ]]; then
echo "Error: BUILDKITE_PIPELINE_SLUG environment variable is not set"
exit 1
fi

# Update CocoaPods's master specs repo (used when you don't use the CDN)
bundle exec pod repo update --verbose
save_cache ~/.cocoapods "$BUILDKITE_PIPELINE_SLUG-specs-repos" --force
save_cache "${HOME}/.cocoapods" "${BUILDKITE_PIPELINE_SLUG}-specs-repos" --force

if [ -f Podfile ]; then
if [[ -f Podfile ]]; then
# Update the cache of the Pods used by the repo.
# Skip if the repo doesn't have a `Podfile` (e.g. lib repo with only a `.podspec`)
bundle exec pod install --verbose
save_cache ~/Library/Caches/CocoaPods/ "$BUILDKITE_PIPELINE_SLUG-global-pod-cache" --force
save_cache "${HOME}/Library/Caches/CocoaPods/" "${BUILDKITE_PIPELINE_SLUG}-global-pod-cache" --force
fi
Loading