Skip to content

Commit 878fe62

Browse files
authored
Merge pull request #17 from gemsiot/zach/system_analysis
Added test framework, test, build, deploy pipeline
2 parents 7b12272 + f1e7ea3 commit 878fe62

67 files changed

Lines changed: 2637 additions & 1361 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# FlightControl Demo GitHub Actions Workflows
2+
3+
This folder contains GitHub Actions workflows for automating the testing, building, and deployment of the FlightControl Demo firmware.
4+
5+
## Automated Workflow Overview
6+
7+
### PR Workflow (`pr-workflow.yaml`)
8+
9+
Triggered in the following scenarios:
10+
- When a pull request is opened, reopened, or updated (synchronize) against the `master` branch
11+
- Manually from the GitHub Actions tab
12+
13+
This workflow has three sequential jobs:
14+
15+
1. **Test**: Runs unit tests using CMake
16+
2. **Compile**: Compiles the firmware for the BSOM platform
17+
3. **Flash**: Flashes the compiled firmware to a test device
18+
19+
Each job only runs if the previous job succeeds, providing a complete validation pipeline for pull requests.
20+
21+
### Release Workflow (`release-workflow.yaml`)
22+
23+
Triggered in the following scenarios:
24+
- When a PR is merged to `master` (note: closing without merging won't trigger the release)
25+
- When code is pushed directly to `master`
26+
- Manually from the GitHub Actions tab
27+
28+
This workflow has two sequential jobs:
29+
30+
1. **Release**:
31+
- Compiles the firmware with auto-versioning
32+
- Commits the updated version file
33+
- Creates a GitHub release with the firmware binary and debug information
34+
35+
2. **Upload**:
36+
- Uploads the firmware to the Particle cloud for OTA updates to production devices
37+
- Only runs if the firmware version was updated in the previous step
38+
39+
## Individual Manual Workflows
40+
41+
These workflows can only be triggered manually from the GitHub Actions tab and are designed for testing individual steps before opening a PR.
42+
43+
### Manual Test (`manual-test.yaml`)
44+
Runs the unit tests on a specific branch.
45+
- **Inputs**:
46+
- Branch to test (optional)
47+
48+
### Manual Compile (`manual-compile.yaml`)
49+
Compiles the firmware on a specific branch.
50+
- **Inputs**:
51+
- Branch to compile (optional)
52+
- **Outputs**:
53+
- Firmware binary as an artifact
54+
55+
### Manual Flash (`manual-flash.yaml`)
56+
Flashes a device with compiled firmware.
57+
- **Inputs**:
58+
- Device ID (optional, defaults to test device)
59+
- Use latest artifact (yes/no)
60+
- **Notes**:
61+
- Can use the firmware from the latest manual-compile run or compile a new binary
62+
63+
### Manual Release (`manual-release.yaml`)
64+
Creates a test release without committing version changes.
65+
- **Inputs**:
66+
- Branch to release (optional)
67+
- Force version increment (yes/no)
68+
- Custom release notes (optional)
69+
- **Notes**:
70+
- Creates a GitHub prerelease with '-manual' tag suffix
71+
- Doesn't commit version changes back to the repository
72+
73+
### Manual Upload (`manual-upload.yaml`)
74+
Uploads a firmware binary to Particle cloud.
75+
- **Inputs**:
76+
- Product ID (optional)
77+
- Firmware version (required)
78+
- Release title (optional)
79+
- Use release artifact (yes/no)
80+
- **Notes**:
81+
- Can use the firmware from the latest manual-release run or compile a new binary
82+
83+
## Manual Workflow Triggering (Main Workflows)
84+
85+
The main workflows can also be triggered manually from the GitHub Actions tab:
86+
87+
1. **PR Workflow**:
88+
- Optional input for the reason for manual testing
89+
90+
2. **Release Workflow**:
91+
- Option to control version increment (yes/no)
92+
- Custom release notes field that overrides the auto-generated ones
93+
94+
## Required Secrets
95+
96+
The workflows require the following secrets to be configured in your GitHub repository:
97+
98+
- `PARTICLE_ACCESS_TOKEN`: Particle cloud API token for uploading firmware
99+
- `PARTICLE_USER_LEVEL_ACCESS_TOKEN`: Particle token for flashing individual test devices
100+
- `PARTICLE_TEST_DEVICE_ID`: ID of the test device to flash during PR testing
101+
- `PARTICLE_PRODUCT_ID`: ID of the Particle product for production releases
102+
103+
## Event Flow
104+
105+
1. **When opening a PR to master**:
106+
- PR Workflow runs (test → compile → flash)
107+
- This validates the changes before they're merged
108+
109+
2. **When merging a PR to master**:
110+
- Release Workflow runs (compile/release → upload)
111+
- This creates a new version, GitHub release, and deploys to Particle
112+
113+
3. **When pushing directly to master**:
114+
- Release Workflow runs (same as merging a PR)
115+
- This is for quick changes that don't require a PR
116+
117+
## Usage Notes
118+
119+
1. For initial testing, use the individual manual workflows to check each step separately
120+
2. Once confident, open a PR to trigger the full PR workflow
121+
3. After reviewing and approving, merge the PR to trigger the release workflow
122+
4. Manual workflows provide a way to test specific stages of the pipeline in isolation
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Manual Compile
2+
3+
# This workflow can only be triggered manually
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
branch:
8+
description: 'Branch to compile'
9+
required: false
10+
default: ''
11+
type: string
12+
13+
jobs:
14+
compile:
15+
name: Compile Firmware
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
ref: ${{ github.event.inputs.branch || github.ref }}
23+
24+
- name: Compile application
25+
id: compile
26+
uses: particle-iot/compile-action@9dbe1eb567c6268f1baa7458217d5d6e5553850d
27+
with:
28+
particle-platform-name: 'bsom'
29+
device-os-version: 6.2.1
30+
31+
- name: Upload artifact
32+
uses: actions/upload-artifact@v4
33+
with:
34+
name: firmware-binary
35+
path: ${{ steps.compile.outputs.firmware-path }}
36+
retention-days: 1
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Manual Flash
2+
3+
# This workflow can only be triggered manually
4+
on:
5+
workflow_dispatch:
6+
branch:
7+
description: 'Branch to compile'
8+
required: false
9+
default: ''
10+
type: string
11+
inputs:
12+
device_id:
13+
description: 'Device ID to flash (defaults to test device)'
14+
required: false
15+
default: ''
16+
type: string
17+
use_latest_artifact:
18+
description: 'Use latest uploaded artifact? (yes/no)'
19+
required: false
20+
default: 'yes'
21+
type: string
22+
23+
jobs:
24+
flash:
25+
name: Flash Device
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
with:
31+
submodules: recursive
32+
ref: ${{ github.event.inputs.branch || github.ref }}
33+
34+
- name: Compile firmware
35+
id: compile
36+
if: github.event.inputs.use_latest_artifact != 'yes'
37+
uses: particle-iot/compile-action@9dbe1eb567c6268f1baa7458217d5d6e5553850d
38+
with:
39+
particle-platform-name: 'bsom'
40+
device-os-version: 6.2.1
41+
42+
- name: Download latest firmware artifact
43+
if: github.event.inputs.use_latest_artifact == 'yes'
44+
uses: dawidd6/action-download-artifact@v3
45+
with:
46+
workflow: manual-compile.yaml
47+
name: firmware-binary
48+
path: ./firmware
49+
50+
- name: Find firmware binary
51+
id: find_binary
52+
run: |
53+
if [ "${{ github.event.inputs.use_latest_artifact }}" == "yes" ]; then
54+
FIRMWARE=$(find ./firmware -name "*.bin" -type f | head -n 1)
55+
else
56+
FIRMWARE="${{ steps.compile.outputs.firmware-path }}"
57+
fi
58+
echo "Using firmware: $FIRMWARE"
59+
echo "firmware-path=$FIRMWARE" >> $GITHUB_OUTPUT
60+
61+
- name: Flash device
62+
uses: zradlicz/flash-device-action@fef2be3306f8a1fa40c75c832e9127513d973f3a
63+
with:
64+
particle-access-token: ${{ secrets.PARTICLE_USER_LEVEL_ACCESS_TOKEN }}
65+
device-id: ${{ github.event.inputs.device_id || secrets.PARTICLE_TEST_DEVICE_ID }}
66+
firmware-path: ${{ steps.find_binary.outputs.firmware-path }}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Manual Release
2+
3+
# This workflow can only be triggered manually
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
branch:
8+
description: 'Branch to release'
9+
required: false
10+
default: ''
11+
type: string
12+
force_version_increment:
13+
description: 'Force version increment'
14+
required: false
15+
default: 'yes'
16+
type: string
17+
release_notes:
18+
description: 'Custom release notes'
19+
required: false
20+
type: string
21+
22+
jobs:
23+
release:
24+
name: Create Release
25+
runs-on: ubuntu-latest
26+
outputs:
27+
firmware-path: ${{ steps.compile.outputs.firmware-path }}
28+
firmware-version: ${{ steps.compile.outputs.firmware-version }}
29+
firmware-version-updated: ${{ steps.compile.outputs.firmware-version-updated }}
30+
release-url: ${{ steps.release.outputs.html_url }}
31+
steps:
32+
- name: Checkout code
33+
uses: actions/checkout@v4
34+
with:
35+
fetch-depth: 0
36+
ref: ${{ github.event.inputs.branch || github.ref }}
37+
38+
- name: Compile application
39+
id: compile
40+
uses: particle-iot/compile-action@v1
41+
with:
42+
particle-platform-name: 'bsom'
43+
auto-version: ${{ github.event.inputs.force_version_increment == 'yes' }}
44+
device-os-version: 6.1.1
45+
46+
- name: Upload artifacts
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: release-artifacts
50+
path: |
51+
${{ steps.compile.outputs.firmware-path }}
52+
${{ steps.compile.outputs.target-path }}
53+
54+
- name: Create archive of target directory
55+
if: steps.compile.outputs.firmware-version-updated == 'true'
56+
run: |
57+
tar -czf debug-objects.tar.gz ${{ steps.compile.outputs.target-path }}
58+
59+
- name: Create GitHub release
60+
id: release
61+
if: steps.compile.outputs.firmware-version-updated == 'true'
62+
uses: ncipollo/release-action@v1
63+
with:
64+
artifacts: ${{ steps.compile.outputs.firmware-path }},debug-objects.tar.gz
65+
generateReleaseNotes: ${{ github.event.inputs.release_notes == '' }}
66+
body: ${{ github.event.inputs.release_notes }}
67+
name: "Firmware v${{ steps.compile.outputs.firmware-version }} (Manual)"
68+
tag: "v${{ steps.compile.outputs.firmware-version }}-manual"
69+
commit: ${{ github.sha }}
70+
token: ${{ secrets.GITHUB_TOKEN }}
71+
prerelease: true

.github/workflows/manual-test.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Manual Test
2+
3+
# This workflow can only be triggered manually
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
branch:
8+
description: 'Branch to test'
9+
required: false
10+
default: ''
11+
type: string
12+
13+
jobs:
14+
test:
15+
name: Run Tests
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
ref: ${{ github.event.inputs.branch || github.ref }}
23+
24+
- name: Install dependencies
25+
run: |
26+
sudo apt-get update
27+
sudo apt-get install -y cmake build-essential
28+
29+
- name: Create build directory
30+
run: mkdir -p build
31+
32+
- name: Configure CMake
33+
run: cd build && cmake ..
34+
35+
- name: Build
36+
run: cd build && cmake --build .
37+
38+
- name: Run tests
39+
run: |
40+
TEST_EXECUTABLE=$(find build -name "unit_tests" -type f -executable)
41+
if [ -n "$TEST_EXECUTABLE" ]; then
42+
$TEST_EXECUTABLE
43+
else
44+
echo "Test executable not found!"
45+
exit 1
46+
fi

0 commit comments

Comments
 (0)