Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ Collection of GitHub actions for ecobee. While the current examples are all comp

| Action |
| ---------------------------------------------------------------------- |
| [`ecobee/github-actions/go_build_artifact@main`](../go_build_artifact) |
| [`ecobee/github-actions/go_test_and_lint@main`](../go_test_and_lint) |
| [`ecobee/github-actions/push_docker_gcr@main`](../push_docker_gcr) |
| [`ecobee/github-actions/go_build_artifact@v1`](./go_build_artifact) |
| [`ecobee/github-actions/go_test_and_lint@v1`](./go_test_and_lint) |
| [`ecobee/github-actions/push_docker_gcr@v1`](./push_docker_gcr) |
| [`ecobee/github-actions/publish_dx_dora_metrics@v1`](./publish_dx_dora_metrics) |

## Usage

Expand All @@ -15,6 +16,50 @@ See individual action directory for details on usage and examples.
- [Go Build artifact](../go_build_artifact) - builds golang binary and outputs build tag
- [Go Test and Lint](../go_test_and_lint) - runs golang tests, and lints with golangci-lint
- [Push Docker GCR](../push_docker_gcr) - creates docker file from repo's Dockerfile, pushed using supplied build tag
- [Publish DX DORA Metrics](../publish_dx_dora_metrics) - publishes deployment metrics to DX for DORA tracking
Comment thread
skawaguchi-ecobee marked this conversation as resolved.

## Versioning

This repository follows [semantic versioning](https://semver.org/). When using these actions in workflows:
- **Recommended:** `@v1` - automatically get non-breaking updates (patches and minor versions)
- **Pinned:** `@v1.0.0` - pin to a specific release version
- **Unstable:** `@main` - use latest code (not recommended for production)

### Creating Releases

For maintainers releasing new versions:

1. **Merge changes to main**
2. **Run the release script:**
```bash
./scripts/set-release-tag.sh v1.2.3
```
The script will:
- Validate you're on `main` with a clean working tree
- Show the current latest version
- Validate the new version is greater than the current version
- Create and push both the version tag (`v1.2.3`) and major tag (`v1`)

> **⚠️ Important:** The release script only validates version format and ordering. **You are responsible for:**
> - Reviewing the changes since the last release
> - Determining if the version bump is appropriate (major/minor/patch)
> - Ensuring breaking changes are properly documented
> - Verifying all actions work as expected
>
> The script is a safeguard against simple mistakes, not a substitute for careful release management.

**Manual alternative:**
```bash
git tag v1.0.0
git push origin v1.0.0
git tag -f v1
git push -f origin v1
```

**Versioning Guidelines:**
- **Major (v2.0.0):** Breaking changes to inputs, outputs, or behavior
- **Minor (v1.1.0):** New features, backward-compatible changes
- **Patch (v1.0.1):** Bug fixes, documentation updates

<!-- ## Changelog

Expand Down
86 changes: 86 additions & 0 deletions publish_dx_dora_metrics_trunk_based/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Publish DX DORA Metrics (Trunk-Based)

Publishes deployment metrics to DX (ecobee.getdx.net) for trunk-based development workflows where code is committed directly to the main branch and deployed.

## Prerequisites

**Required Secret:** `DX_API_TOKEN` is configured as a GitHub organizational secret.

This secret is managed centrally by the SRE team and is automatically available to all repositories in the ecobee organization.

## Usage

```yaml
- name: Publish DORA metrics
uses: ecobee/github-actions/publish_dx_dora_metrics_trunk_based@v1
continue-on-error: true
env:
DX_API_TOKEN: ${{ secrets.DX_API_TOKEN }}
with:
repository: 'ecobee/my-service'
service: 'my-service'
# Optional: defaults to 'production' - only needed for testing
environment: 'staging'
```

> **Note:** Use `@v1` for the latest stable version, `@v1.0.0` to pin to a specific release, or `@main` for the latest (unstable) version.
>
> **Important:** Use `continue-on-error: true` to prevent metrics tracking failures from blocking deployments.

## Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `repository` | Repository identifier (e.g., `ecobee/service-name`) | Yes | - |
| `environment` | Deployment environment | No | `production` |
| `service` | Service identifier | Yes | - |

> **Note:** The action automatically extracts the commit timestamp from git for change lead time tracking.

## Environment Variables

| Variable | Description | Required | Source |
|----------|-------------|----------|--------|
| `DX_API_TOKEN` | DX API token for authentication | Yes | GitHub organizational secret |

## Example Workflow

```yaml
name: Deploy to Production

on:
push:
branches:
- main

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# ... your deployment steps ...

- name: Publish deployment metrics
uses: ecobee/github-actions/publish_dx_dora_metrics_trunk_based@v1
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Figured we need to start having versioning. I'm anticipating creating more shared actions as we go.

continue-on-error: true
env:
DX_API_TOKEN: ${{ secrets.DX_API_TOKEN }}
with:
repository: 'ecobee/my-service'
service: 'my-service'
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to keep this as simple as possible for teams to use.

```

## Versioning

This action follows [semantic versioning](https://semver.org/). When integrating:
- Use `@v1` to automatically get non-breaking updates (recommended)
- Use `@v1.0.0` to pin to a specific release
- Avoid `@main` in production workflows (unstable)

## Security Notes

- The `DX_API_TOKEN` is **never** passed as an action input to prevent accidental exposure in logs
- The token is configured as a GitHub organizational secret, managed centrally by the SRE team
- The action will fail explicitly if the token is not available
- Never commit tokens or credentials to the repository
79 changes: 79 additions & 0 deletions publish_dx_dora_metrics_trunk_based/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: 'Publish DX DORA Metrics (Trunk-Based)'
description: 'Publishes deployment metrics to DX for trunk-based development workflows. Requires DX_API_TOKEN organizational secret which is managed globally by the SRE team. Teams should not have to worry about it.'
inputs:
repository:
description: 'Repository identifier (e.g., ecobee/op-ts-server-core, ecobee/service-home)'
required: true
environment:
description: 'Deployment environment (defaults to production)'
required: false
default: 'production'
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what's needed to show up in DORA. I've made it overridable so we can test connections by querying in DX and setting this to like "test" and it won't affect our actual DORA metrics.

service:
description: 'Service identifier (e.g. communicator, service-home)'
required: true
runs:
using: 'composite'
steps:
- name: Publish deployment to DX
env:
REPOSITORY: ${{ inputs.repository }}
ENVIRONMENT: ${{ inputs.environment }}
SERVICE: ${{ inputs.service }}
COMMIT_SHA: ${{ github.sha }}
run: |
set -euo pipefail

# Validate required inputs
if [ -z "$REPOSITORY" ]; then
echo "::error::repository input is required"
exit 1
fi

if [ -z "$SERVICE" ]; then
echo "::error::service input is required"
exit 1
fi

if [ -z "$COMMIT_SHA" ]; then
echo "::error::commit-sha input is required"
exit 1
fi

# Validate DX_API_TOKEN is available
if [ -z "$DX_API_TOKEN" ]; then
echo "::error::DX_API_TOKEN environment variable is not set. This should be configured as an organizational secret by the SRE team"
exit 1
fi

# Get commit timestamp from git
COMMIT_TIMESTAMP_UNIX=$(git show -s --format=%ct "$COMMIT_SHA")

# Always use current time for deployment
DEPLOYED_AT_UNIX=$(date +%s)

# Construct JSON payload safely using jq
PAYLOAD=$(jq -n \
--arg repo "$REPOSITORY" \
--arg env "$ENVIRONMENT" \
--arg svc "$SERVICE" \
--arg sha "$COMMIT_SHA" \
--argjson ts "$DEPLOYED_AT_UNIX" \
--argjson ct "$COMMIT_TIMESTAMP_UNIX" \
'{
repository: $repo,
environment: $env,
service: {identifier: $svc},
commit_sha: $sha,
deployed_at: $ts,
metadata: {
commit_timestamp: $ct
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets us DORA lead time as far as I can tell from the docs

}
}')

# Make API call (fails automatically on 4xx/5xx)
curl --fail --silent --show-error \
-X POST "https://ecobee.getdx.net/api/deployments.create" \
-H "Authorization: Bearer ${DX_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD"
shell: bash
139 changes: 139 additions & 0 deletions scripts/set-release-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/usr/bin/env bash
set -euo pipefail

# Simple release script for github-actions
# Usage: ./scripts/set-release-tag.sh <version>

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

error() {
echo -e "${RED}ERROR: $1${NC}" >&2
exit 1
}

info() {
echo -e "${GREEN}$1${NC}"
}

warn() {
echo -e "${YELLOW}$1${NC}"
}

# Compare semver versions
# Returns 0 if $1 > $2, 1 otherwise
version_gt() {
local ver1=$1
local ver2=$2

# Strip 'v' prefix if present
ver1=${ver1#v}
ver2=${ver2#v}

# Split into major.minor.patch
IFS='.' read -ra V1 <<< "$ver1"
IFS='.' read -ra V2 <<< "$ver2"

# Compare major
if [[ ${V1[0]} -gt ${V2[0]} ]]; then return 0; fi
if [[ ${V1[0]} -lt ${V2[0]} ]]; then return 1; fi

# Compare minor
if [[ ${V1[1]:-0} -gt ${V2[1]:-0} ]]; then return 0; fi
if [[ ${V1[1]:-0} -lt ${V2[1]:-0} ]]; then return 1; fi

# Compare patch
if [[ ${V1[2]:-0} -gt ${V2[2]:-0} ]]; then return 0; fi

return 1
}

# Validate semver format
validate_semver() {
local version=$1
if [[ ! $version =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
error "Invalid version format: $version (expected: v1.2.3)"
fi
}

main() {
# Check we're on main branch
local current_branch=$(git branch --show-current)
if [[ "$current_branch" != "main" ]]; then
error "Must be on 'main' branch to publish (currently on: $current_branch)"
fi

# Fetch latest tags
info "Fetching latest tags..."
git fetch --tags

# Get latest version tag
local latest_tag=$(git tag -l "v*.*.*" | sort -V | tail -n1)

if [[ -z "$latest_tag" ]]; then
warn "No existing version tags found. This will be the first release."
latest_tag="v0.0.0"
else
info "Latest version: $latest_tag"
fi

# Get new version (required)
local new_version="${1:-}"
if [[ -z "$new_version" ]]; then
error "Version argument required. Usage: ./scripts/set-release-tag.sh v1.2.3"
fi

# Validate format
validate_semver "$new_version"

# Check if tag already exists
if git rev-parse "$new_version" >/dev/null 2>&1; then
error "Tag $new_version already exists"
fi

# Validate new version is greater than latest
if [[ "$latest_tag" != "v0.0.0" ]]; then
if ! version_gt "$new_version" "$latest_tag"; then
error "New version $new_version must be greater than $latest_tag"
fi
fi

# Extract major version for major tag (e.g., v1 from v1.2.3)
local major_version=$(echo "$new_version" | sed -E 's/^v([0-9]+)\..*/v\1/')

echo ""
info "Release Summary:"
echo " Previous: $latest_tag"
echo " New: $new_version"
echo " Major: $major_version (will be updated)"
echo ""

read -p "Create and push these tags? (y/N): " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
warn "Release cancelled"
exit 0
fi

# Create and push version tag
info "Creating tag $new_version..."
git tag "$new_version"
git push origin "$new_version"

# Update major version tag
info "Updating major version tag $major_version..."
git tag -f "$major_version"
git push -f origin "$major_version"

echo ""
info "✓ Release complete!"
echo ""
echo "Tags created:"
echo " - $new_version"
echo " - $major_version"
echo ""
echo "Teams can now use: @$major_version or @$new_version"
}

main "$@"