Skip to content

Commit 321aea8

Browse files
authored
Set up repo to generate terraform module releases (#3)
## Summary: This PR sets up a simple versioning system for our Terraform modules repository. ### What's Added - **Manual Release Workflow** - GitHub Action to create module releases - Go to Actions → Manual Release - Enter module name, version number, and optional release notes - Creates git tags and GitHub releases automatically - **Dependabot Configuration** - Automatic updates for: - Terraform provider versions - GitHub Actions versions ### How to Use When you want to release a module version: 1. Go to Actions → Manual Release 2. Enter module name (e.g., `scheduled-function`) 3. Enter version (e.g., `1.0.0`) 4. Add release notes (optional) 5. Run workflow This creates a git tag like `scheduled-function-v1.0.0` and a GitHub release with usage instructions. ### Benefits - No complex workflows or commit message requirements - Automatic dependency updates via Dependabot - Clean release process with proper git tags - Generated usage instructions for each release Check [Releases](../../releases) page to see available module versions. Issue: INFRA-10715 ## Test plan: n/a, will be tested in following PRs that add modules Author: jwbron Reviewers: csilvers, jwbron Required Reviewers: Approved By: csilvers Checks: ✅ 1 check was successful Pull Request URL: #3
1 parent 328da81 commit 321aea8

File tree

7 files changed

+314
-17
lines changed

7 files changed

+314
-17
lines changed

.github/CONTRIBUTING.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
1-
This repository is not accepting contributions. We’re releasing the code for others
2-
to refer to and learn from, but we are not open to pull requests or issues at
3-
this time.
4-
5-
Khan Academy is a non-profit organization with a mission to provide a free,
6-
world-class education to anyone, anywhere. You can help us in that mission by
7-
[donating](https://khanacademy.org/donate) or looking at
8-
[career opportunities](https://khanacademy.org/careers).
1+
# Contributing to Terraform Modules
2+
3+
## Development Workflow
4+
5+
1. Fork and clone the repository
6+
2. Create a feature branch from `main`
7+
3. Make your changes to modules in `terraform/modules/`
8+
4. Submit a pull request
9+
10+
## Releases
11+
12+
Releases are created manually using the **Manual Release** GitHub Action:
13+
14+
1. Go to Actions → Manual Release
15+
2. Select the module name (e.g., `scheduled-function`)
16+
3. Enter version number (e.g., `1.0.0`)
17+
4. Add optional release notes in the text field
18+
5. Run the workflow
19+
20+
### Release Notes
21+
22+
Release notes are added through the workflow input field and support markdown formatting. Include:
23+
24+
```markdown
25+
## What's Changed
26+
- New feature: Description of new functionality
27+
- Bug fix: Description of what was fixed
28+
- Breaking change: Description of breaking changes
29+
30+
## Upgrade Notes
31+
- Any special instructions for upgrading
32+
- Migration steps if needed
33+
```
34+
35+
The workflow automatically adds usage instructions to every release.

.github/workflows/gerald-push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
gerald:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v2
12+
- uses: actions/checkout@v4
1313
with:
1414
ref: '${{ github.ref }}'
1515
# GitHub Actions doesn't allow us to take the length of github.event.commits, so we have to pass the array into node and take the length there.

.github/workflows/lint.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- master
7+
push:
8+
branches:
9+
- master
10+
11+
jobs:
12+
pr-test:
13+
name: Lint
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install dependencies and lint
19+
run: make lint

.github/workflows/manual-release.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Manual Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
module:
7+
description: 'Module name to release (e.g., scheduled-function)'
8+
required: true
9+
type: string
10+
version:
11+
description: 'Version number (e.g., 1.0.0)'
12+
required: true
13+
type: string
14+
release_notes:
15+
description: 'Release notes (optional)'
16+
required: false
17+
type: string
18+
19+
permissions:
20+
contents: write
21+
22+
jobs:
23+
validate-input:
24+
name: Validate Input
25+
runs-on: ubuntu-latest
26+
outputs:
27+
module-exists: ${{ steps.check-module.outputs.exists }}
28+
version-valid: ${{ steps.check-version.outputs.valid }}
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v4
32+
33+
- name: Check if module exists
34+
id: check-module
35+
run: |
36+
if [ -d "terraform/modules/${{ github.event.inputs.module }}" ]; then
37+
echo "exists=true" >> $GITHUB_OUTPUT
38+
echo "Module ${{ github.event.inputs.module }} exists"
39+
else
40+
echo "exists=false" >> $GITHUB_OUTPUT
41+
echo "ERROR: Module ${{ github.event.inputs.module }} does not exist"
42+
exit 1
43+
fi
44+
45+
- name: Validate version format
46+
id: check-version
47+
run: |
48+
version="${{ github.event.inputs.version }}"
49+
if [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
50+
echo "valid=true" >> $GITHUB_OUTPUT
51+
echo "Version format is valid: $version"
52+
else
53+
echo "valid=false" >> $GITHUB_OUTPUT
54+
echo "ERROR: Version format is invalid: $version (expected format: x.y.z)"
55+
exit 1
56+
fi
57+
58+
create-release:
59+
name: Create Release
60+
runs-on: ubuntu-latest
61+
needs: validate-input
62+
if: needs.validate-input.outputs.module-exists == 'true' && needs.validate-input.outputs.version-valid == 'true'
63+
steps:
64+
- name: Checkout
65+
uses: actions/checkout@v4
66+
with:
67+
fetch-depth: 0
68+
69+
- name: Check version constraints
70+
run: |
71+
module="${{ github.event.inputs.module }}"
72+
new_version="${{ github.event.inputs.version }}"
73+
tag_name="$module-v$new_version"
74+
75+
# Check if exact tag already exists
76+
if git tag -l | grep -q "^$tag_name$"; then
77+
echo "ERROR: Tag $tag_name already exists"
78+
exit 1
79+
fi
80+
81+
# Get latest version for this module
82+
latest_tag=$(git tag -l "${module}-v*" | sort -V | tail -n1)
83+
84+
if [ -n "$latest_tag" ]; then
85+
latest_version=${latest_tag#${module}-v}
86+
echo "Latest existing version: $latest_version"
87+
echo "New version: $new_version"
88+
89+
# Compare versions using sort -V (version sort)
90+
higher_version=$(echo -e "$latest_version\n$new_version" | sort -V | tail -n1)
91+
92+
if [ "$higher_version" = "$latest_version" ] && [ "$new_version" != "$latest_version" ]; then
93+
echo "ERROR: New version $new_version is not greater than latest version $latest_version"
94+
echo "Next valid versions would be:"
95+
96+
# Suggest next versions
97+
IFS='.' read -r major minor patch <<< "$latest_version"
98+
echo " - Patch: $major.$minor.$((patch + 1))"
99+
echo " - Minor: $major.$((minor + 1)).0"
100+
echo " - Major: $((major + 1)).0.0"
101+
exit 1
102+
fi
103+
else
104+
echo "No existing versions found for module $module"
105+
fi
106+
107+
echo "Version $new_version is valid and available"
108+
109+
- name: Generate release notes
110+
id: generate-notes
111+
run: |
112+
module="${{ github.event.inputs.module }}"
113+
version="${{ github.event.inputs.version }}"
114+
user_notes="${{ github.event.inputs.release_notes }}"
115+
116+
# Create release notes
117+
{
118+
echo "# $module v$version"
119+
echo ""
120+
if [ -n "$user_notes" ]; then
121+
echo "$user_notes"
122+
echo ""
123+
fi
124+
echo "## Usage"
125+
echo ""
126+
echo '```hcl'
127+
echo "module \"$module\" {"
128+
echo " source = \"git::https://github.com/${{ github.repository }}.git//terraform/modules/$module?ref=$module-v$version\""
129+
echo " "
130+
echo " # Module configuration"
131+
echo "}"
132+
echo '```'
133+
} > release_notes.md
134+
135+
- name: Create Release
136+
uses: softprops/action-gh-release@v2
137+
with:
138+
tag_name: ${{ github.event.inputs.module }}-v${{ github.event.inputs.version }}
139+
name: "${{ github.event.inputs.module }} v${{ github.event.inputs.version }}"
140+
body_path: release_notes.md
141+
draft: false
142+
prerelease: false

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,5 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
.venv

Makefile

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Tool versions
2+
TERRAFORM_VERSION := 1.8.0
3+
TFLINT_VERSION := 0.51.1
4+
ACTIONLINT_VERSION := 1.7.7
5+
6+
# OS and architecture detection
7+
OS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
8+
ARCH := $(shell uname -m | sed 's/x86_64/amd64/; s/arm64/arm64/')
9+
10+
VENV := .venv
11+
12+
# Terraform variables
13+
TF_WORKSPACE ?= default
14+
TF_DIR := terraform
15+
16+
.PHONY: deps
17+
deps:
18+
@mkdir -p ${VENV}/bin
19+
20+
.PHONY: tflint-install
21+
tflint-install: deps
22+
@if ! command -v ${VENV}/bin/tflint >/dev/null 2>&1 || [ "$$(${VENV}/bin/tflint --version | head -1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')" != "${TFLINT_VERSION}" ]; then \
23+
echo "Installing tflint v${TFLINT_VERSION}..."; \
24+
echo "Downloading for OS: ${OS}, ARCH: ${ARCH}"; \
25+
mkdir -p ${VENV}/bin; \
26+
pushd ${VENV}/bin; \
27+
curl -sL "https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/tflint_${OS}_${ARCH}.zip" -o tflint.zip; \
28+
unzip -o tflint.zip; \
29+
rm tflint.zip; \
30+
chmod +x tflint; \
31+
popd; \
32+
${VENV}/bin/tflint --init; \
33+
fi
34+
35+
.PHONY: terraform-install
36+
terraform-install: deps
37+
@if ! command -v ${VENV}/bin/terraform >/dev/null 2>&1 || [ "$$(${VENV}/bin/terraform version -json | jq -r '.terraform_version')" != "${TERRAFORM_VERSION}" ]; then \
38+
echo "Installing terraform v${TERRAFORM_VERSION}..."; \
39+
echo "Downloading for OS: ${OS}, ARCH: ${ARCH}"; \
40+
mkdir -p ${VENV}/bin; \
41+
pushd ${VENV}/bin; \
42+
curl -sL "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_${OS}_${ARCH}.zip" -o terraform.zip; \
43+
unzip -o terraform.zip; \
44+
rm terraform.zip; \
45+
chmod +x terraform; \
46+
popd; \
47+
fi
48+
49+
.PHONY: actionlint-install
50+
actionlint-install: deps
51+
@if ! command -v ${VENV}/bin/actionlint >/dev/null 2>&1 || [ "$$(${VENV}/bin/actionlint -version 2>/dev/null | head -1)" != "${ACTIONLINT_VERSION}" ]; then \
52+
echo "Installing actionlint v${ACTIONLINT_VERSION}..."; \
53+
echo "Downloading for OS: ${OS}, ARCH: ${ARCH}"; \
54+
mkdir -p ${VENV}/bin; \
55+
pushd ${VENV}/bin; \
56+
curl -sL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_${OS}_${ARCH}.tar.gz" -o actionlint.tar.gz; \
57+
tar xzf actionlint.tar.gz; \
58+
rm actionlint.tar.gz; \
59+
chmod +x actionlint; \
60+
popd; \
61+
fi
62+
63+
.PHONY: lint
64+
lint: tflint-install terraform-install actionlint-install
65+
PATH=${VENV}/bin:$$PATH tflint --recursive
66+
PATH=${VENV}/bin:$$PATH terraform fmt -recursive -check
67+
PATH=${VENV}/bin:$$PATH actionlint $(git rev-parse --show-toplevel)
68+
69+
.PHONY: fix
70+
fix: tflint-install terraform-install actionlint-install
71+
PATH=${VENV}/bin:$$PATH tflint --recursive --fix
72+
PATH=${VENV}/bin:$$PATH terraform fmt -recursive
73+
PATH=${VENV}/bin:$$PATH actionlint $(git rev-parse --show-toplevel)

README.md

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
1-
This repository is not accepting contributions. We’re releasing the code for others
2-
to refer to and learn from, but we are not open to pull requests or issues at
3-
this time.
4-
5-
Khan Academy is a non-profit organization with a mission to provide a free,
6-
world-class education to anyone, anywhere. You can help us in that mission by
7-
[donating](https://khanacademy.org/donate) or looking at
8-
[career opportunities](https://khanacademy.org/careers).
1+
# Terraform Modules
2+
3+
This repository contains shared, reusable Terraform modules designed to simplify infrastructure provisioning and promote consistency across projects.
4+
5+
## Overview
6+
7+
These modules encapsulate common infrastructure patterns and best practices, allowing teams to quickly deploy standardized resources without duplicating configuration code.
8+
9+
## Usage
10+
11+
To use a module from this repository, reference it in your Terraform configuration with a specific version:
12+
13+
```hcl
14+
module "scheduled_function" {
15+
source = "git::https://github.com/your-org/terraform-modules.git//terraform/modules/scheduled-function?ref=v1.0.0"
16+
17+
# Module-specific variables
18+
function_name = "my-scheduled-function"
19+
schedule_expression = "rate(1 hour)"
20+
}
21+
```
22+
23+
Always use a specific version tag (e.g., `?ref=v1.0.0`) to ensure consistent deployments and avoid unexpected changes.
24+
25+
## Structure
26+
27+
Each module is self-contained in its own directory under `terraform/modules/` and includes:
28+
- **main.tf** - Primary resource definitions
29+
- **variables.tf** - Input variable declarations
30+
- **outputs.tf** - Output value definitions
31+
- **versions.tf** - Provider version constraints
32+
- **README.md** - Module-specific documentation (auto-generated)
33+
- **CHANGELOG.md** - Module changelog (auto-generated)
34+
- **examples/** - Usage examples and test cases
35+
36+
## Versioning
37+
38+
Module versions are managed manually using GitHub Actions.
39+
40+
See the [Contributing Guide](.github/CONTRIBUTING.md#releases) for details on creating releases.
41+
42+
Check the [Releases](../../releases) page for available versions.

0 commit comments

Comments
 (0)