Skip to content

Commit e857dae

Browse files
authored
ci: consolidate workflow for local testing with act (#9)
- Add skip_build workflow input to support local testing scenarios - Create dual integration test jobs (normal CI and local image) - Add integration-tests-local job for testing locally-built images - Add scripts/build-local-arm64.sh for Apple Silicon native builds - Update CONTRIBUTING.md with local testing documentation - Fix markdown linting issues in CONTRIBUTING.md - Update test structure documentation to reflect current setup
1 parent c589e32 commit e857dae

3 files changed

Lines changed: 177 additions & 25 deletions

File tree

.github/workflows/ci.yml

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ on:
2020
required: false
2121
default: false
2222
type: boolean
23+
skip_build:
24+
description: "Skip build and use local image (for local testing with act)"
25+
required: false
26+
default: false
27+
type: boolean
2328

2429
jobs:
2530
# ============================================
@@ -121,6 +126,7 @@ jobs:
121126
name: Integration Tests
122127
runs-on: ubuntu-latest
123128
needs: build-test-image
129+
if: ${{ !inputs.skip_build }}
124130
steps:
125131
- name: Checkout repository
126132
uses: actions/checkout@v4
@@ -146,19 +152,65 @@ jobs:
146152
sudo ./install.sh /usr/local
147153
148154
- name: Run integration tests
149-
env:
150-
CI: true
151155
run: bats tests/integration/
152156

157+
integration-tests-local:
158+
name: Integration Tests (Local Image)
159+
runs-on: ubuntu-latest
160+
if: ${{ inputs.skip_build }}
161+
steps:
162+
- name: Checkout repository
163+
uses: actions/checkout@v4
164+
165+
- name: Verify Docker image exists
166+
run: |
167+
echo "Checking for locally-built Docker image..."
168+
if docker images | grep -q "jmcombs/powershell.*latest"; then
169+
echo "✅ Found jmcombs/powershell:latest"
170+
docker images | grep powershell
171+
else
172+
echo "❌ Error: jmcombs/powershell:latest not found"
173+
echo ""
174+
echo "Please build the image first:"
175+
echo " ./scripts/build-local-arm64.sh"
176+
exit 1
177+
fi
178+
179+
- name: Install bats-core
180+
run: |
181+
git clone https://github.com/bats-core/bats-core.git /tmp/bats-core
182+
cd /tmp/bats-core
183+
sudo ./install.sh /usr/local
184+
185+
- name: Run integration tests
186+
run: bats tests/integration/
187+
188+
- name: Test summary
189+
if: always()
190+
run: |
191+
echo ""
192+
echo "================================================"
193+
echo "Integration Tests Complete"
194+
echo "================================================"
195+
echo ""
196+
echo "Image tested: jmcombs/powershell:latest"
197+
docker images | grep powershell || true
198+
153199
# ============================================
154200
# Stage 4: Publish (only on main, after tests)
155201
# ============================================
156202

157203
publish:
158204
name: Build and Publish
159205
runs-on: ubuntu-latest
160-
needs: integration-tests
161-
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
206+
needs: [integration-tests, integration-tests-local]
207+
if: |
208+
always() &&
209+
github.ref == 'refs/heads/main' &&
210+
github.event_name != 'pull_request' &&
211+
!inputs.skip_build &&
212+
(needs.integration-tests.result == 'success' || needs.integration-tests.result == 'skipped') &&
213+
(needs.integration-tests-local.result == 'success' || needs.integration-tests-local.result == 'skipped')
162214
permissions:
163215
contents: write
164216
steps:

CONTRIBUTING.md

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,27 @@ This project maintains LTS versions of PowerShell Core and .NET Core in Linux co
3232
### Local Development
3333

3434
1. **Clone the repository**:
35+
3536
```bash
3637
git clone https://github.com/jmcombs/powershell.git
3738
cd powershell
3839
```
3940

4041
2. **Install testing dependencies**:
42+
4143
```bash
4244
# Install bats-core for testing
4345
git clone https://github.com/bats-core/bats-core.git
4446
cd bats-core && sudo ./install.sh /usr/local
4547
cd .. && rm -rf bats-core
46-
48+
4749
# Install shellcheck for script validation
4850
sudo apt-get install shellcheck # Ubuntu/Debian
4951
brew install shellcheck # macOS
5052
```
5153

5254
3. **Make scripts executable**:
55+
5356
```bash
5457
chmod +x scripts/*.sh
5558
```
@@ -60,16 +63,12 @@ This project uses a comprehensive testing strategy with multiple test types:
6063

6164
### Test Structure
6265

63-
```
66+
```text
6467
tests/
6568
├── test_helper.bash # Common test utilities and setup
66-
├── mocks/ # Mock data for testing
67-
│ ├── dotnet_releases_index.json
68-
│ ├── dotnet_releases.json
69-
│ └── powershell_release.json
70-
├── unit/ # Unit tests with mocked dependencies
69+
├── unit/ # Offline unit tests (no network calls)
7170
│ └── test_get_net_pwsh_versions.bats
72-
└── integration/ # Integration tests with real network calls
71+
└── integration/ # Integration tests with live network calls
7372
└── test_script_integration.bats
7473
```
7574

@@ -90,17 +89,25 @@ bats tests/unit/test_get_net_pwsh_versions.bats
9089
bats -t tests/
9190
```
9291

92+
### Local Testing on Apple Silicon
93+
94+
For developers using Apple Silicon (M-series) Macs:
95+
96+
- **Automated build and test**: Run `./scripts/build-local-arm64.sh` to build the Docker image natively for ARM64 and automatically run all integration tests using `act`
97+
- **Why this is needed**: The main CI workflow builds for AMD64 (x86_64), which causes QEMU emulation issues on Apple Silicon. The build script uses a consolidated workflow with `skip_build=true` to test against locally-built ARM64 images
98+
- **Manual testing**: After building, run `act workflow_dispatch --pull=false --input skip_build=true -j integration-tests-local` to execute integration tests independently
99+
93100
### Test Categories
94101

95-
1. **Unit Tests**: Test individual functions with mocked dependencies
102+
1. **Unit Tests**: Test individual helper functions and local behavior
96103
- Fast execution
97104
- No network dependencies
98-
- Test edge cases and error conditions
105+
- Validate script structure, env-file helpers, and version format logic
99106

100-
2. **Integration Tests**: Test complete workflows with real API calls
107+
2. **Integration Tests**: Test complete workflows with live API calls and the built container image
101108
- Slower execution
102-
- Require network access
103-
- Test real-world scenarios
109+
- Require network access and Docker
110+
- Validate real-world .NET and PowerShell LTS discovery and build args
104111

105112
3. **Script Validation**: Static analysis and syntax checking
106113
- Shellcheck for bash script quality
@@ -111,19 +118,19 @@ bats -t tests/
111118

112119
When adding new functionality:
113120

114-
1. **Write unit tests first** for new functions
115-
2. **Add integration tests** for end-to-end workflows
116-
3. **Update mock data** if API responses change
117-
4. **Test error conditions** and edge cases
121+
1. **Write unit tests first** for new helper functions and local behavior
122+
2. **Add integration tests** for end-to-end workflows that depend on external services
123+
3. **Test error conditions** and edge cases, especially around network failures and malformed responses
118124

119125
Example test structure:
126+
120127
```bash
121128
@test "descriptive test name" {
122129
# Arrange: Set up test conditions
123-
130+
124131
# Act: Execute the code being tested
125132
run your_function_or_command
126-
133+
127134
# Assert: Verify the results
128135
[ "$status" -eq 0 ]
129136
[[ "$output" =~ "expected pattern" ]]
@@ -141,7 +148,7 @@ Example test structure:
141148
- Use meaningful function and variable names
142149
- Add comments for complex logic
143150

144-
### Testing
151+
### Test Guidelines
145152

146153
- Use descriptive test names that explain what is being tested
147154
- Group related tests in the same file
@@ -153,6 +160,7 @@ Example test structure:
153160
### Branch Naming
154161

155162
Use descriptive branch names with prefixes:
163+
156164
- `feature/description` - New features
157165
- `fix/description` - Bug fixes
158166
- `test/description` - Test improvements
@@ -161,7 +169,8 @@ Use descriptive branch names with prefixes:
161169
### Commit Messages
162170

163171
Follow conventional commit format:
164-
```
172+
173+
```text
165174
type(scope): description
166175
167176
Longer explanation if needed
@@ -197,6 +206,7 @@ Types: `feat`, `fix`, `test`, `docs`, `ci`, `refactor`
197206
### Bug Reports
198207

199208
Use the bug report template and include:
209+
200210
- Clear description of the issue
201211
- Steps to reproduce
202212
- Expected vs actual behavior
@@ -206,6 +216,7 @@ Use the bug report template and include:
206216
### Feature Requests
207217

208218
Use the feature request template and include:
219+
209220
- Clear description of the proposed feature
210221
- Use case and motivation
211222
- Possible implementation approach

scripts/build-local-arm64.sh

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Build Docker image locally for ARM64 (Apple Silicon)
5+
# This script builds the image natively without QEMU emulation issues
6+
7+
echo "🔧 Building PowerShell Docker image for ARM64 (Apple Silicon)..."
8+
9+
# Get version information
10+
echo "📋 Getting .NET and PowerShell versions..."
11+
chmod +x ./scripts/get-net-pwsh-versions.sh
12+
./scripts/get-net-pwsh-versions.sh
13+
14+
# Source the environment variables
15+
if [ -f /tmp/env_vars ]; then
16+
echo "✅ Loading build arguments from /tmp/env_vars"
17+
export $(cat /tmp/env_vars | xargs)
18+
else
19+
echo "❌ Error: /tmp/env_vars not found"
20+
exit 1
21+
fi
22+
23+
# Build the image for ARM64
24+
echo "🐳 Building Docker image for linux/arm64..."
25+
docker buildx build \
26+
--platform linux/arm64 \
27+
--build-arg NET_RUNTIME_LTS_VERSION="${NET_RUNTIME_LTS_VERSION}" \
28+
--build-arg NET_RUNTIME_URL_arm="${NET_RUNTIME_URL_arm}" \
29+
--build-arg NET_RUNTIME_PACKAGE_NAME_arm="${NET_RUNTIME_PACKAGE_NAME_arm}" \
30+
--build-arg NET_RUNTIME_URL_arm64="${NET_RUNTIME_URL_arm64}" \
31+
--build-arg NET_RUNTIME_PACKAGE_NAME_arm64="${NET_RUNTIME_PACKAGE_NAME_arm64}" \
32+
--build-arg NET_RUNTIME_URL_x64="${NET_RUNTIME_URL_x64}" \
33+
--build-arg NET_RUNTIME_PACKAGE_NAME_x64="${NET_RUNTIME_PACKAGE_NAME_x64}" \
34+
--build-arg PWSH_LTS_URL_arm32="${PWSH_LTS_URL_arm32}" \
35+
--build-arg PWSH_LTS_PACKAGE_NAME_arm32="${PWSH_LTS_PACKAGE_NAME_arm32}" \
36+
--build-arg PWSH_LTS_URL_arm64="${PWSH_LTS_URL_arm64}" \
37+
--build-arg PWSH_LTS_PACKAGE_NAME_arm64="${PWSH_LTS_PACKAGE_NAME_arm64}" \
38+
--build-arg PWSH_LTS_URL_x64="${PWSH_LTS_URL_x64}" \
39+
--build-arg PWSH_LTS_PACKAGE_NAME_x64="${PWSH_LTS_PACKAGE_NAME_x64}" \
40+
--build-arg PWSH_LTS_VERSION="${PWSH_LTS_VERSION}" \
41+
--build-arg PWSH_LTS_MAJOR_VERSION="${PWSH_LTS_MAJOR_VERSION}" \
42+
--load \
43+
--tag jmcombs/powershell:test \
44+
--tag jmcombs/powershell:latest \
45+
.
46+
47+
echo ""
48+
echo "✅ Build complete!"
49+
echo ""
50+
echo "📦 Tagged images:"
51+
echo " - jmcombs/powershell:test"
52+
echo " - jmcombs/powershell:latest"
53+
echo ""
54+
55+
# Tag the image as 'latest' for integration tests
56+
echo "🏷️ Tagging image as latest for integration tests..."
57+
docker tag jmcombs/powershell:test jmcombs/powershell:latest
58+
59+
# Run integration tests with act using the main CI workflow with skip_build input
60+
echo "🧪 Running integration tests with act..."
61+
echo ""
62+
63+
if command -v act &> /dev/null; then
64+
# Use the main ci.yml workflow with skip_build=true to bypass the build job
65+
# This runs the integration-tests-local job which assumes the image already exists
66+
act workflow_dispatch --pull=false --input skip_build=true -j integration-tests-local
67+
TEST_EXIT_CODE=$?
68+
69+
echo ""
70+
if [ $TEST_EXIT_CODE -eq 0 ]; then
71+
echo "✅ All integration tests passed!"
72+
else
73+
echo "❌ Integration tests failed with exit code: $TEST_EXIT_CODE"
74+
exit $TEST_EXIT_CODE
75+
fi
76+
else
77+
echo "⚠️ Warning: 'act' is not installed. Skipping integration tests."
78+
echo ""
79+
echo " Install act with:"
80+
echo " brew install act"
81+
echo ""
82+
echo " To run tests manually:"
83+
echo " act workflow_dispatch --pull=false --input skip_build=true -j integration-tests-local"
84+
fi
85+
86+
echo ""
87+
echo "🚀 To run the container:"
88+
echo " docker run -it jmcombs/powershell:latest"
89+

0 commit comments

Comments
 (0)