Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jlucktay/stack
A support tool for use with Terraform stacks, Azure DevOps build pipelines, and GitHub projects/repos.
https://github.com/jlucktay/stack
azure-devops cli github terraform
Last synced: about 23 hours ago
JSON representation
A support tool for use with Terraform stacks, Azure DevOps build pipelines, and GitHub projects/repos.
- Host: GitHub
- URL: https://github.com/jlucktay/stack
- Owner: jlucktay
- License: mit
- Created: 2019-07-05T14:47:18.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2024-02-12T13:51:19.000Z (about 1 year ago)
- Last Synced: 2025-02-08T12:09:12.866Z (6 days ago)
- Topics: azure-devops, cli, github, terraform
- Language: Go
- Homepage:
- Size: 522 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 18
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
- Codeowners: CODEOWNERS
Awesome Lists containing this project
README
# `stack`
[![Go][actions-badge]][actions]
[![Go Report Card][goreportcard-badge]][goreportcard]
[![PkgGoDev][pkggodev-badge]][pkggodev]
[![Contribute][contrib-badge]][contrib]
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blueviolet.svg)](http://makeapullrequest.com)A support tool for use with Terraform stacks, Azure DevOps build pipelines, and GitHub projects/repos.
It currently has the following functions:
- initialising Terraform against remote state storage, for local execution
- queueing Terraform plans to build and destroy stacks in an Azure DevOps CI/CD pipeline
- cancelling unneeded releases of aforementioned builds
- creating GitHub issues in corresponding projectsAll of these functions are executed contextually against a specific Terraform stack directory.
## Installation
There are numerous installation options for `stack`:
- [Homebrew](https://brew.sh)
- building from the source code hosted here
- directly downloading a pre-built binary for your desired platform### Homebrew
#### First time install
```shell
brew install jlucktay/tap/stack
```#### Ongoing upgrades
```shell
brew upgrade jlucktay/tap/stack
```### Building from source
#### Prerequisites
You should have a [working Go environment](https://golang.org/doc/install) and have `$GOPATH/bin` in your `$PATH`.
#### Compiling
To download the source, compile, and install the demo binary, run:
```shell
go get go.jlucktay.dev/stack
```A newly-compiled `stack` binary will be placed in `$GOPATH/bin/`.
### Direct download of binary relases
Binary releases can be downloaded [here on GitHub](https://github.com/jlucktay/stack/releases/latest).
## Configuration
There is a sample JSON file named `stack.config.example.json` here in the root of this repo.
The search order that `stack` follows when looking for the fully populated `stack.config.json` config file is as
follows:1. `/stack.config.json`
1. `$HOME/.config/stack/stack.config.json`
1. `/etc/stack/stack.config.json`Filling out this config file will require the generation of two personal access tokens, one from Azure DevOps and one
from GitHub. Links to the appropriate pages on each site are in the example file.### Mapping subscriptions to remote state storage containers and keys
Under the `.azure.subscriptions` section, all keys defined here will map verbatim to the parent directory's name when
`stack` is executed. The values need to be set as GUIDs for the corresponding subscriptions in Azure.Assume - for this example's sake - that the working directory is as follows:
```bash
/git/MyGitHubOrg/MyGitHubRepo/stack-prefix/subscription-alias/one/two/three/my-stack
```Also assume that the following values are configured:
```json
{
"azure": {
"state": {
"storageAccount": "mytfstatestorage"
},
"subscriptions": {
"subscription-alias": "01234567-89ab-cdef-0123-456789abcdef"
}
},
"github": {
"org": "MyGitHubOrg",
"repo": "MyGitHubRepo"
},
"stackPrefix": "stack-prefix"
}
```The keys under `.azure.subscriptions` map to the first child directory underneath the directory set under
`.stackPrefix` so the sub-directory `subscription-alias` (under `stack-prefix`) would map to the subscription with a
GUID of `01234567-89ab-cdef-0123-456789abcdef`.For remote state storage within the storage account, the key value is made up of three components:
1. the `.stackPrefix` value (`stack-prefix` in this example)
1. the name of the stack's direct parent directory (`three`)
1. the name of the stack directory itself (`my-stack`)The container within the remote state storage account maps to the GUID of the subscription.
```bash
$ pwd
/git/MyGitHubOrg/MyGitHubRepo/stack-prefix/subscription-alias/one/two/three/my-stack
$ stack init
Switching subscriptions... done.
Retrieving storage account key... done.
Switching subscriptions... done.
Initialising Terraform with following dynamic values:
container_name: 01234567-89ab-cdef-0123-456789abcdef
key: stack-prefix.three.my-stack
storage_account: mytfstatestorage
...
```### Other tools in use
Some of the functionality in `stack` comes from executing other tools, which will need to be installed, configured,
authed, and available on your `$PATH`:- [Git](https://git-scm.com) - `git`
- [Terraform](https://www.terraform.io) - `terraform`## Usage
`stack` itself has several subcommands:
- `init`
- `build`
- `destroy`
- `cancel`
- `issue`
- `version`### `stack init`
Initialises the current Terraform stack directory using the Azure storage account for the remote state backend.
```bash
$ stack init
Switching subscriptions... done.
Retrieving storage account key... done.
Switching subscriptions... done.
Initialising Terraform with following dynamic values:
...
```#### `stack init` relevant config keys
```json
{
"azure": {
"state": {
"keyPrefix": "first of three segments for key names of state files within blob storage",
"resourceGroup": "name of resource group on Azure which contains the storage account",
"storageAccount": "name of Azure storage account where Terraform state is stored",
"subscription": "GUID of Azure subscription holding the state storage account"
},
"subscriptions": {
"a stack under '////'": "will map to subscription associated with ",
"exampleSubName": "subscription GUIDs go here",
"this key will be matched to a parent directory": "this value will map said directory to a specific subscription"
}
},
"stackPrefix": "/some/segment/of/repo/directory/structure/"
}
```### `stack build`
Queues a plan in Azure DevOps to build the Terraform stack in the current directory.
```bash
$ stack build
Stack (plan) URL: https://dev.azure.com/MyAzureDevOpsOrg/12345678-90ab-cdef-1234-567890abcdef/_build/results?buildId=1234
```#### `stack build` relevant config keys
```json
{
"azureDevOps": {
"buildDefID": 5,
"org": "the name of the organisation within Azure DevOps",
"pat": "52 character alphanumeric, generated here: https://dev.azure.com//_usersSettings/tokens",
"project": "the name of the project under the organisation within Azure DevOps"
},
"stackPrefix": "/some/segment/of/repo/directory/structure/"
}
```#### `stack build` optional arguments
##### `--branch`
If given, build from this branch. Defaults to the current branch.
##### `--target`
If given, target these specific Terraform resources only. Delimit multiple target IDs with a comma `,`.
For example:```bash
stack build --target="azurerm_resource_group.main,azurerm_virtual_machine.app,azurerm_virtual_machine.database"
```### `stack destroy`
Queues a plan in Azure DevOps to destroy the Terraform stack in the current directory.
Functionally identical to the `stack build` subcommand, including `--branch` and `--target` optional arguments, with
the singular difference being that this subcommand references `.azureDevOps.destroyDefID` in the config instead of
`.azureDevOps.buildDefID`.### `stack cancel`
Cancels any pending releases in Azure DevOps.
**Not yet implemented - coming soon!**
### `stack issue`
Creates an issue in GitHub with a label referring to the current Terraform stack directory, and assigned to the
current user.The issue's body text is gathered by way of an interactive editor, designated by the current environment's `EDITOR`
variable.```bash
$ stack issue -t "There's a problem with this stack!"
...
($EDITOR is launched to gather issue body)
...
New issue: https://github.com/MyGitHubOrg/MyGitHubRepo/issues/1234
```#### `stack issue` relevant config keys
```json
{
"github": {
"org": "the name of the organisation within GitHub",
"pat": "<40 character hexadecimal, generated here: https://github.com/settings/tokens>",
"repo": "the name of the repository under the organisation within GitHub"
}
}
```### `stack version`
Displays version and build information for the current `stack` binary.
## Docker
There is a [Dockerfile](Dockerfile) that is looped into `make` and will be built by the default rule.
A typical execution of the Docker image from within your own stack directory needs to mount a volume under `/workdir`
and would look something like this:```shell
docker run --rm --volume $(pwd):/workdir go.jlucktay.dev/stack[:]
```The subcommands [described above](#usage) may be passed in by appending them to this command line, for example:
```shell
docker run --rm --volume $(pwd):/workdir go.jlucktay.dev/stack[:] version
```## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
See also the [contributing guide](.github/CONTRIBUTING.md).
## License
[MIT](https://choosealicense.com/licenses/mit/)
[actions-badge]: https://github.com/jlucktay/stack/actions/workflows/go.yaml/badge.svg
[actions]: https://github.com/jlucktay/stack/actions/workflows/go.yaml
[contrib-badge]: https://img.shields.io/github/contributors/jlucktay/stack
[contrib]: https://github.com/jlucktay/stack/tree/main/.github/CONTRIBUTING.md
[goreportcard-badge]: https://goreportcard.com/badge/go.jlucktay.dev/stack
[goreportcard]: https://goreportcard.com/report/go.jlucktay.dev/stack
[pkggodev-badge]: https://pkg.go.dev/badge/go.jlucktay.dev/stack
[pkggodev]: https://pkg.go.dev/go.jlucktay.dev/stack