This project runs acceptance tests against a separate incident-io-terraform account, with its own isolated Slack workspace.
The account is empty and marked as a demo to enable all feature gates.
If you work at incident.io as an engineer, you may wish to develop this provider against your own local instance of the product, such as when building Terraform resources for as-yet released features.
You can do this by:
- Getting an API key with the relevant scopes from your local instance
- Running tests with the following environment set:
export INCIDENT_ENDPOINT="https://incident-io-name.eu.ngrok.io/api/public"
export INCIDENT_API_KEY="inc_development_<token>"Note
If you're using mise you can set these variables in .env
This points the provider at your local instance via ngrok.
If you need to regenerate the client, you first need to copy the following file from core:
# If your core repository is one level up, this would be:
cp ../core/server/lib/openapi/public-schema-v3-including-secret-endpoints.json internal/apischema
And then run go generate ./internal/client
The best way to develop against this provider is to write tests.
Tests run against a real API, either the production/staging incident.io API or whatever you may be running locally (for incident.io staff). If you're staff, it's best to use a localhost endpoint for lower latency if possible.
To run the tests:
# Run the whole suite
$> make testacc
# Run a single test
$> make testacc TESTARGS=-run=TestAccIncidentEscalationPathResourceIf you're running with a debugger use make debug instead:
# Debug the whole suite
$> make testacc
# Debug a single test
$> make testacc TESTARGS=-run=TestAccIncidentEscalationPathResourceTo run the tests with GoLand & Mise:
- Install the Mise plugin
- Add a new
Go TestRun Configuration - In the
Misetab of the Run Configuration, checkUse environment variables from mise - In the
Configurationtab, add an environment variableTF_ACC=1
Note
In CI, we do not run tests that require integrations to be installed
on the test account, to minimise flakiness. To run these tests locally, add
extra environment variables (e.g. TF_ACC_JIRA=1).
Some tests require existing resources to be present in the test account, which we can't create from the test setup. For example, a Slack channel ID or a Team catalog type. Set these up using these variables:
export TF_ACC_CHANNEL_ID=C07U7JMC29J
export TF_TEAM_TYPE_NAME=Team
There may be changes where you want to be running the provider itself, rather than just running tests. To do that you need to:
- Install Terraform:
brew install hashicorp/tap/terraform- Create yourself a project
mkdir tmp/project
- Create a
dev.tfrcfile, insidetmp/projectso thatterraformuses your local version of the provider:
provider_installation {
dev_overrides {
"incident-io/incident" = "/<PATH-TO-REPO>/terraform-provider-incident/bin"
}
direct {}
}
- Create a
main.tffile including any resources that you want to create (look inexamples/resourcesfor some nice examples)
terraform {
required_providers {
incident = {
source = "incident-io/incident"
version = "~> 5"
}
}
}
provider "incident" {}
resource "incident_catalog_type" "service_tier" {
name = "Service Tier"
description = "Level of importance for each service"
source_repo_url = "https://github.com/incident-io/terraform-provider-incident"
}
- Build the provider binary
make build- Start your
terraformserver:
TF_CLI_CONFIG_FILE=./dev.tfrc terraform init
- You can now plan and apply your Terraform configuration:
TF_CLI_CONFIG_FILE=./dev.tfrc terraform plan
TF_CLI_CONFIG_FILE=./dev.tfrc terraform apply
Use Optional: true when the user doesn't need to specify an attribute in their config. For example,
external_id on incident_catalog_entry_resource. Catalog entries don't have to have an external ID,
so we don't make users set one in their terraform config.
Use Computed: true when we generate a value for this attribute if the user doesn't specify one. For
example, type_name on incident_catalog_type_resource. If the user specifies a type name for a catalog
type, we'll use it. If they don't, we'll generate one based on the name of the type.
Use Default when you want to use a particular value for the attribute during planning when the user
hasn't specified a value. For example, team_ids on incident_schedule_resource defaults to an empty set:
Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})),
This means when planning, we compare the team IDs that the API returns against the empty set if no team IDs are specified. This is useful for avoiding any state mismatch problems when you introduce a new attribute to an existing resource.
Use the UseStateForUnknown plan modifier when there's an attribute value that the user can't specify,
but you want to avoid the plan being littered with "Known after apply". For example, this is very useful
for ID attributes like on incident_schedule_resource:
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
MarkdownDescription: apischema.Docstring("ScheduleV2", "id"),
},
When planning, we'll have an ID in state for each schedule, and this plan modifier will copy the ID from the state in to the planned value, avoiding the "Known after apply" warning.