first commit after fork

This commit is contained in:
Robert Kaussow 2024-02-05 20:44:47 +01:00
parent 24156d51b0
commit fc8c16ac5e
Signed by: xoxys
GPG Key ID: 4E692A2EAECC03C0
43 changed files with 1763 additions and 1688 deletions

2
.dictionary Normal file
View File

@ -0,0 +1,2 @@
OpenTofu
wp-opentofu

View File

@ -1,3 +0,0 @@
.git
build-docker.sh
CHANGELOG.md

View File

@ -1,12 +0,0 @@
workspace:
base: /go
path: src/github.com/drone-plugins/drone-terraform
pipeline:
test:
image: golang:1.9
environment:
- CGO_ENABLED=0
commands:
- go test -cover -coverprofile=coverage.out
- go build -ldflags "-s -w -X main.revision=$(git rev-parse HEAD)" -a

26
.editorconfig Normal file
View File

@ -0,0 +1,26 @@
# https://editorconfig.org/
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[Makefile]
indent_style = tab
indent_size = 4
[*.{go,mod}]
indent_style = tab
tab_width = 4
[*.star]
indent_style = space
indent_size = 4
[LICENSE]
indent_size = unset

71
.github/settings.yml vendored Normal file
View File

@ -0,0 +1,71 @@
repository:
name: wp-opentofu
description: Woodpecker CI plugin to manage infrastructure with OpenTofu
homepage: https://woodpecker-plugins.geekdocs.de/plugins/wp-opentofu
topics: woodpecker-ci, woodpecker, woodpecker-plugin
private: false
has_issues: true
has_wiki: false
has_downloads: true
default_branch: main
allow_squash_merge: true
allow_merge_commit: true
allow_rebase_merge: true
labels:
- name: bug
color: d73a4a
description: Something isn't working
- name: documentation
color: 0075ca
description: Improvements or additions to documentation
- name: duplicate
color: cfd3d7
description: This issue or pull request already exists
- name: enhancement
color: a2eeef
description: New feature or request
- name: good first issue
color: 7057ff
description: Good for newcomers
- name: help wanted
color: 008672
description: Extra attention is needed
- name: invalid
color: e4e669
description: This doesn't seem right
- name: question
color: d876e3
description: Further information is requested
- name: wontfix
color: ffffff
description: This will not be worked on
branches:
- name: main
protection:
required_pull_request_reviews: null
required_status_checks:
strict: false
contexts:
- ci/woodpecker/pr/test
- ci/woodpecker/pr/build-package
- ci/woodpecker/pr/build-container
- ci/woodpecker/pr/docs
enforce_admins: false
required_linear_history: true
restrictions: null
- name: docs
protection:
required_pull_request_reviews: null
required_status_checks: null
enforce_admins: true
required_linear_history: true
restrictions:
apps: []
users: []
teams:
- bot

30
.gitignore vendored
View File

@ -1,27 +1,7 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
/dist
/release
/wp-opentofu*
docs/data/data-raw.yaml
coverage.out
drone-terraform
CHANGELOG.md

47
.gitsv/config.yml Normal file
View File

@ -0,0 +1,47 @@
---
version: "1.1"
versioning:
update-major: []
update-minor: [feat]
update-patch: [fix, perf, refactor, chore, test, ci, docs]
tag:
pattern: "v%d.%d.%d"
release-notes:
sections:
- name: Features
commit-types: [feat]
section-type: commits
- name: Bug Fixes
commit-types: [fix]
section-type: commits
- name: Performance Improvements
commit-types: [perf]
section-type: commits
- name: Code Refactoring
commit-types: [refactor]
section-type: commits
- name: Others
commit-types: [chore]
section-type: commits
- name: Testing
commit-types: [test]
section-type: commits
- name: CI Pipeline
commit-types: [ci]
section-type: commits
- name: Documentation
commit-types: [docs]
section-type: commits
- name: BREAKING CHANGES
section-type: breaking-changes
commit-message:
footer:
issue:
key: issue
add-value-prefix: "#"
issue:
regex: "#?[0-9]+"

101
.golangci.yml Normal file
View File

@ -0,0 +1,101 @@
linters:
enable-all: false
disable-all: true
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- decorder
- dogsled
- dupl
- dupword
- durationcheck
- errchkjson
- errname
- errorlint
- execinquery
- exhaustive
- exportloopref
- forcetypeassert
- ginkgolinter
- gocheckcompilerdirectives
- gochecknoglobals
- gochecknoinits
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- godox
- goerr113
- gofmt
- gofumpt
- goheader
- goimports
- gomnd
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- grouper
- importas
- interfacebloat
- ireturn
- lll
- loggercheck
- maintidx
- makezero
- misspell
- musttag
- nakedret
- nestif
- nilerr
- nilnil
- nlreturn
- noctx
- nolintlint
- nonamedreturns
- nosprintfhostport
- prealloc
- predeclared
- promlinter
- reassign
- revive
# - rowserrcheck
# - sqlclosecheck
# - structcheck
- stylecheck
- tagliatelle
- tenv
- testableexamples
- thelper
- tparallel
- unconvert
- unparam
- usestdlibvars
# - wastedassign
- whitespace
- wsl
- zerologlint
fast: false
run:
timeout: 3m
linters-settings:
tagliatelle:
case:
rules:
json: kebab
gofumpt:
extra-rules: true

6
.markdownlint.yml Normal file
View File

@ -0,0 +1,6 @@
---
default: True
MD013: False
MD041: False
MD004:
style: dash

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
*.tpl.md
LICENSE

View File

@ -0,0 +1,69 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [push]
branch:
- renovate/*
steps:
- name: dryrun
image: quay.io/thegeeklab/wp-docker-buildx:3
settings:
containerfile: Containerfile.multiarch
dry_run: true
platforms:
- linux/amd64
- linux/arm64
provenance: false
repo: ${CI_REPO}
when:
- event: [pull_request]
- name: publish-dockerhub
image: quay.io/thegeeklab/wp-docker-buildx:3
group: container
settings:
auto_tag: true
containerfile: Containerfile.multiarch
password:
from_secret: docker_password
platforms:
- linux/amd64
- linux/arm64
provenance: false
repo: ${CI_REPO}
username:
from_secret: docker_username
when:
- event: [tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- name: publish-quay
image: quay.io/thegeeklab/wp-docker-buildx:3
group: container
settings:
auto_tag: true
containerfile: Containerfile.multiarch
password:
from_secret: quay_password
platforms:
- linux/amd64
- linux/arm64
provenance: false
registry: quay.io
repo: quay.io/${CI_REPO}
username:
from_secret: quay_username
when:
- event: [tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
depends_on:
- test

View File

@ -0,0 +1,44 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [push]
branch:
- renovate/*
steps:
- name: build
image: docker.io/techknowlogick/xgo:go-1.21.x
commands:
- ln -s $(pwd) /source
- make release
- name: executable
image: quay.io/thegeeklab/alpine-tools
commands:
- $(find dist/ -executable -type f -iname ${CI_REPO_NAME}-linux-amd64) --help
- name: changelog
image: quay.io/thegeeklab/git-sv
commands:
- git sv current-version
- git sv release-notes -t ${CI_COMMIT_TAG:-next} -o CHANGELOG.md
- cat CHANGELOG.md
- name: publish-github
image: docker.io/plugins/github-release
settings:
api_key:
from_secret: github_token
files:
- dist/*
note: CHANGELOG.md
overwrite: true
title: ${CI_COMMIT_TAG}
when:
- event: [tag]
depends_on:
- test

83
.woodpecker/docs.yml Normal file
View File

@ -0,0 +1,83 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [push]
branch:
- renovate/*
steps:
- name: markdownlint
image: quay.io/thegeeklab/markdownlint-cli
group: test
commands:
- markdownlint 'README.md' 'CONTRIBUTING.md'
- name: spellcheck
image: quay.io/thegeeklab/alpine-tools
group: test
commands:
- spellchecker --files 'docs/**/*.md' 'README.md' 'CONTRIBUTING.md' -d .dictionary -p spell indefinite-article syntax-urls
environment:
FORCE_COLOR: "true"
- name: link-validation
image: docker.io/lycheeverse/lychee
group: test
commands:
- lychee --no-progress --format detailed docs/content README.md
- name: publish
image: quay.io/thegeeklab/wp-git-action
settings:
action:
- pages
author_email: bot@thegeeklab.de
author_name: thegeeklab-bot
branch: docs
message: "[skip ci] auto-update documentation"
netrc_password:
from_secret: github_token
pages_directory: docs/
when:
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
status: [success, failure]
- name: pushrm-dockerhub
image: docker.io/chko/docker-pushrm:1
secrets:
- source: docker_password
target: DOCKER_PASS
- source: docker_username
target: DOCKER_USER
environment:
PUSHRM_FILE: README.md
PUSHRM_SHORT: Woodpecker CI plugin to manage infrastructure with OpenTofu
PUSHRM_TARGET: ${CI_REPO}
when:
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
status: [success]
- name: pushrm-quay
image: docker.io/chko/docker-pushrm:1
secrets:
- source: quay_token
target: APIKEY__QUAY_IO
environment:
PUSHRM_FILE: README.md
PUSHRM_TARGET: quay.io/${CI_REPO}
when:
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
status: [success]
depends_on:
- build-package
- build-container

26
.woodpecker/notify.yml Normal file
View File

@ -0,0 +1,26 @@
---
when:
- event: [tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
runs_on: [success, failure]
steps:
- name: matrix
image: quay.io/thegeeklab/wp-matrix
settings:
homeserver:
from_secret: matrix_homeserver
password:
from_secret: matrix_password
roomid:
from_secret: matrix_roomid
username:
from_secret: matrix_username
when:
- status: [success, failure]
depends_on:
- docs

20
.woodpecker/test.yml Normal file
View File

@ -0,0 +1,20 @@
---
when:
- event: [pull_request, tag]
- event: [push, manual]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [push]
branch:
- renovate/*
steps:
- name: lint
image: docker.io/library/golang:1.21
commands:
- make lint
- name: test
image: docker.io/library/golang:1.21
commands:
- make test

View File

@ -1,120 +0,0 @@
## 8.3-1.0.2 (2021-07-09)
* Update embedded TF to `1.0.2`
* A continuation of `v0.15` release line but now following semver
* Please refer to [Terraform v1.0 Compatibility Promises](https://www.terraform.io/docs/language/v1-compatibility-promises.html)
## 8.3-0.15.1 (2021-07-09)
* fix: remove -lock and -lock-timeout for terraform init - https://github.com/jmccann/drone-terraform/pull/130
## 8.2-0.15.1 (2021-06-02)
* fix: `-force` -> `-auto-approve` - https://github.com/jmccann/drone-terraform/pull/128
## 8.1-0.15.1 (2021-04-27)
* added ability to [disable refresh](https://github.com/jmccann/drone-terraform/pull/120)
## 8.0-0.15.1 (2021-04-27)
* Update embedded TF to `0.15.1`
* Please refer to [Terraform v15 Migration Guide](https://www.terraform.io/upgrade-guides/0-15.html)
* Update other deps
## 7.0-0.14.11 (2021-04-27)
* Update embedded TF to `0.14.11`
* Please refer to [Terraform v14 Migration Guide](https://www.terraform.io/upgrade-guides/0-14.html)
## 6.4-0.13.2 (2020-09-11)
* Update embedded TF to `0.13.2`
## 6.4-0.13.1 (2020-09-11)
* minor version bump due to major version change of terraform
* Update embedded TF to `0.13.1`
* added curl
## 6.3-0.12.20 (2020-02-12)
* add ability to load creds from `env_file` parameter (https://github.com/jmccann/drone-terraform/pull/107). Thanks @neemiasjnr!
## 6.2-0.12.20 (2020-02-05)
* Update embedded TF to `0.12.20`
* Update alpine to 3.11 in docker image (https://github.com/jmccann/drone-terraform/pull/109). Thanks @sgerrand!
## 6.2-0.12.16 (2019-11-26)
* Update embedded TF to `0.12.16`
## 6.2-0.12.11 (2019-11-26)
* tfValidate vars and var-file argument removal #106 Thanks @gsingh1
## 6.1-0.12.11 (2019-10-18)
* Update embedded TF to `0.12.11`
## 6.1-0.12.10 (2019-10-15)
* Update embedded TF to `0.12.10`
## 6.1-0.12.8 (2019-09-06)
* Support for parallel execution (https://github.com/jmccann/drone-terraform/pull/94). Thanks @caioquirino!
* Updated golang to 1.13
## 6.0-0.12.8 (2019-09-06)
* Update embedded TF to `0.12.8`
## 6.0-0.12.6 (2019-08-05)
* Update embedded TF to `0.12.6`
## 6.0-0.12.4 (2019-07-12)
* Update embedded TF to `0.12.4`
## 6.0-0.12.1 (2019-06-05)
* Version bump plugin to `6.0` since terraform `0.12` has breaking changes
* Update embedded TF to `0.12.1`
## 5.3-0.11.14 (2019-08-05)
* Update embedded TF to `0.11.14`
## 5.2-0.11.13 (2019-03-27)
* Update embedded TF to `0.11.13`
## 5.2-0.11.11 (2019-02-22)
* Add `fmt` action
## 5.1-0.11.11 (2019-01-18)
* Update embedded TF to `0.11.11`
## 5.1-0.11.8 (2018-10-11)
* Update embedded TF to `0.11.8`
## 5.1-0.11.7 (2018-07-31)
* Add `vars` and `var_files` to destroy operation
## 5.0-0.11.7 (2018-04-25)
**BREAKING CHANGE**
* Removed `destroy` param
* Removed `plan` param
* Added `actions` param to provide a list of actions to perform.
See [DOCS.md](DOCS.md) for more info and examples.
## 4.1-0.11.7 (2018-04-25)
* Add .netrc support
* Update embedded TF to `0.11.7`
## 4.0-0.11.3 (2018-02-07)
* Update embedded TF to `0.11.3`
## 4.0-0.10.8 (2018-02-07)
* Pass `-var-file` to validate command
* Update embedded TF to `0.10.8`
## 4.0-0.10.7 (2017-10-20)
* Persist state locking config (https://github.com/jmccann/drone-terraform/pull/55)
* Update embedded TF to `0.10.7`
## 4.0-0.10.3 (2017-09-06)
**Breaking Change**
* Update embedded TF to 0.10.3
* In order to support validate in TF 0.10.3 add `vars` to validate command.
This is not compatible with older versions of TF.
## 3.0-0.9.11 (2017-09-06)
**Breaking Change**
* Removed `secrets` key
**Added Features**
* Added support for `destroy`
* Add ability to specify TF version to use via `tf_version`

31
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,31 @@
# Contributing
## Security
If you think you have found a **security issue**, please do not mention it in this repository.
Instead, send an email to `security@thegeeklab.de` with as many details as possible so it can be handled confidential.
## Bug Reports and Feature Requests
If you have found a **bug** or have a **feature request** please use the search first in case a similar issue already exists.
If not, please create an issue in this repository
## Code
If you would like to fix a bug or implement a feature, please fork the repository and create a Pull Request.
Before you start any Pull Request, it is recommended that you create an issue to discuss first if you have any
doubts about requirement or implementation. That way you can be sure that the maintainer(s) agree on what to change and how,
and you can hopefully get a quick merge afterwards.
Pull Requests can only be merged once all status checks are green.
## Do not force push to your Pull Request branch
Please do not force push to your Pull Requests branch after you have created your Pull Request, as doing so makes it harder for us to review your work.
Pull Requests will always be squashed by us when we merge your work. Commit as many times as you need in your Pull Request branch.
## Re-requesting a review
Please do not ping your reviewer(s) by mentioning them in a new comment. Instead, use the re-request review functionality.
Read more about this in the [GitHub docs, Re-requesting a review](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request#re-requesting-a-review).

37
Containerfile.multiarch Normal file
View File

@ -0,0 +1,37 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.21@sha256:7b575fe0d9c2e01553b04d9de8ffea6d35ca3ab3380d2a8db2acc8f0f1519a53 as build
ARG TARGETOS
ARG TARGETARCH
ADD . /src
WORKDIR /src
RUN make build
FROM docker.io/alpine:3.19
LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>"
LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>"
LABEL org.opencontainers.image.title="wp-opentofu"
LABEL org.opencontainers.image.url="https://github.com/thegeeklab/wp-opentofu"
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/wp-opentofu"
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/wp-opentofu"
ARG TARGETOS
ARG TARGETARCH
ARG TOFU_VERSION
# renovate: datasource=github-releases depName=opentofu/opentofu
ENV TOFU_VERSION="${TOFU_VERSION:-v1.6.0}"
RUN apk --update add --virtual .build-deps curl libarchive-tools && \
curl -SsfL "https://github.com/opentofu/opentofu/releases/download/${TOFU_VERSION}/tofu_${TOFU_VERSION##v}_linux_amd64.zip" | \
bsdtar -xf - -C /usr/local/bin tofu && \
chmod 755 /usr/local/bin/tofu && \
apk del .build-deps && \
rm -rf /var/cache/apk/* && \
rm -rf /tmp/* && \
rm -rf /root/.cache/
COPY --from=build /src/dist/wp-opentofu /bin/wp-opentofu
ENTRYPOINT ["/bin/wp-opentofu"]

274
DOCS.md
View File

@ -1,274 +0,0 @@
---
date: 2016-01-01T00:00:00+00:00
title: Terraform
author: jmccann
tags: [ infrastructure, build tool ]
repo: jmccann/drone-terraform
logo: terraform.svg
image: jmccann/drone-terraform
---
The Terraform plugin applies the infrastructure configuration contained within the repository. The below pipeline configuration demonstrates simple usage which will run a `validate`, `plan` and `apply`:
```yaml
pipeline:
terraform:
image: jmccann/drone-terraform:5
```
Example configuration passing `vars` to terraform commands:
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ vars:
+ app_name: my-project
+ app_version: 1.0.0
```
Example of explicitly specifying `actions` to perform a dry run.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ actions:
+ - validate
+ - plan
```
Example configuration passing secrets to terraform. Please read
https://www.terraform.io/docs/configuration/variables.html#environment-variables
for more details.
**Drone 0.6+**:
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ secrets:
+ - source: terraform_secret
+ target: tf_var_my_secret
```
**Drone 0.5**:
```diff
pipeline:
terraform_1:
image: jmccann/drone-terraform:5
+ environment:
+ TF_VAR_MY_SECRET: ${TERRAFORM_SECRET}
terraform_2:
image: jmccann/drone-terraform:5
plan: false
+ sensitive: true
+ vars:
+ my_secret: ${TERRAFORM_SECRET}
```
You may be passing sensitive vars to your terraform commands. If you do not want
the terraform commands to display in your drone logs then set `sensitive` to `true`.
The output from the commands themselves will still display, it just won't show
what command is actually being ran.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ sensitive: true
```
Example configuration for overriding the terraform version. This will increase
plugin execution time as it will download/unpack the version of terraform
specified instead of using the embedded version that is included.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ tf_version: 0.10.3
```
Example configuration with state tracked via remote. You will need a
[backend configuration](https://www.terraform.io/docs/backends/config.html)
specified in a `.tf` file. You can then pass additional options via the `.drone.yml`.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ init_options:
+ backend-config:
+ - "bucket=my-terraform-config-bucket"
+ - "key=tf-states/my-project"
+ - "region=us-east-1"
```
You may want to run terraform against internal resources, like an internal
OpenStack deployment. Sometimes these resources are signed by an internal
CA Certificate. You can inject your CA Certificate into the plugin by using
`ca_certs` key as described above. Below is an example.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ ca_cert: |
+ -----BEGIN CERTIFICATE-----
+ asdfsadf
+ asdfsadf
+ -----END CERTIFICATE-------
```
You may want to assume another role before running the terraform commands.
This is useful for cross account access, where a central account has privileges
to assume roles in other accounts. Using the current credentials, this role will
be assumed and exported to environment variables.
See [the discussion](https://github.com/hashicorp/terraform/issues/1275) in the Terraform issues.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ role_arn_to_assume: arn:aws:iam::account-of-role-to-assume:role/name-of-role
```
You may want to change directories before applying the terraform commands.
This parameter is useful if you have multiple environments in different folders
and you want to use different drone configurations to apply different environments.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ root_dir: some/path/here
```
You may want to only target a specific list of resources within your terraform
code. To achieve this you can specify the `targets` parameter. If left undefined
all resources will be planned/applied against as the default behavior.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ targets:
+ - aws_security_group.generic_sg
+ - aws_security_group.app_sg
```
You may want to limit the number of concurrent operations as Terraform walks its graph.
If you want to change Terraform's default parallelism (currently equal to 10) then set the `parallelism` parameter.
```diff
pipeline:
terraform:
image: jmccann/drone-terraform:5
+ parallelism: 2
```
Destroying the service can be done by specifying `plan-destroy` and `destroy` actions. Keep in mind that Fastly won't allow a service with active version be destroyed. Use `force_destroy` option in the service definition for terraform to handle it.
```diff
pipeline:
destroy:
image: jmccann/drone-terraform:5
+ actions:
+ - plan-destroy
+ - destroy
```
Formatting the Terraform configuration files can be done by specifying the `fmt` action. Use `fmt_options` parameter to handle formatting options.
```diff
pipeline:
fmt:
image: jmccann/drone-terraform:5
+ actions:
+ - fmt
+ fmt_options:
+ write: false
+ diff: true
+ check: true
```
You may want to run some executions in parallel without having racing condition problems with the .terraform dir and
plan's output file.
```diff
pipeline:
backend-service:
image: jmccann/drone-terraform:<version>
+ tf_data_dir: .backend-service.terraform
frontend-service:
image: jmccann/drone-terraform:<version>
+ tf_data_dir: .frontend-service.terraform
```
# Parameter Reference
actions
: List of terraform actions to perform with the plugin. List includes:
`fmt`, `validate`, `plan`, `apply`, `plan-destroy`, `destroy`.
init_options
: contains the configuration for the Terraform backend.
init_options.backend-config
: This specifies additional configuration to merge for the backend. This can be
specified multiple times. Flags specified later in the line override those
specified earlier if they conflict.
init_options.lock
: Lock the state file when locking is supported. Default `true`.
init_options.lock-timeout
: Duration to wait for a state lock. Default `0s`.
fmt_options
: contains the configuration for the fmt action.
fmt_options.list
: List files whose formatting differs (disabled if using STDIN). Default `true`.
fmt_options.write
: Write result to source file instead of STDOUT (disabled if using STDIN or -check). Default `true`.
fmt_options.diff
: Display diffs of formatting changes. Default `false`.
fmt_options.check
: Check if the input is formatted. Exit status will be 0 if all input is properly formatted and non-zero otherwise. Default `false`.
vars
: a map of variables to pass to the Terraform `plan` and `apply` commands.
Each value is passed as a `-var <key>=<value>` option.
var_files
: a list of variable files to pass to the Terraform `plan` and `apply` commands.
Each value is passed as a `-var-file <value>` option.
ca_cert
: ca cert to add to your environment to allow terraform to use internal/private resources
sensitive
: (default: `false`) - Whether or not to suppress terraform commands to stdout.
role_arn_to_assume
: A role to assume before running the terraform commands.
root_dir
: The root directory where the terraform files live. When unset, the top level directory will be assumed.
parallelism
: The number of concurrent operations as Terraform walks its graph.
tf_data_dir
: changes the location where Terraform keeps its per-working-directory data, such as the current remote backend configuration.
disable_refresh
: (default: `false`) - whether or not to disable refreshing state before `plan` and `apply` commands.

View File

@ -1,33 +0,0 @@
# Docker image for the Drone Terraform plugin
#
# docker build -t jmccann/drone-terraform:latest .
FROM golang:1.16-alpine AS builder
RUN apk add --no-cache git
WORKDIR /tmp/drone-terraform
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -o /go/bin/drone-terraform
FROM alpine:3.13
RUN apk add --no-cache \
ca-certificates \
git \
wget \
curl \
openssh-client
ARG terraform_version
RUN wget -q https://releases.hashicorp.com/terraform/${terraform_version}/terraform_${terraform_version}_linux_amd64.zip -O terraform.zip && \
unzip terraform.zip -d /bin && \
rm -f terraform.zip
COPY --from=builder /go/bin/drone-terraform /bin/
ENTRYPOINT ["/bin/drone-terraform"]

View File

@ -1,4 +1,5 @@
Apache License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@ -178,7 +179,7 @@ Apache License
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
@ -186,7 +187,7 @@ Apache License
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Copyright 2023 Robert Kaussow <mail@thegeeklab.de>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,46 +0,0 @@
[people]
[people.bradrydzewski]
name = "Brad Rydzewski"
email = "brad@drone.io"
login = "bradrydzewski"
[people.Bugagazavr]
name = "Kirill"
email = ""
login = "Bugagazavr"
[people.donny-dont]
name = "Don Olmstead"
email = "donny-dont@gmail.com"
login = "donny-dont"
[people.jackspirou]
name = "Jack Spirou"
email = ""
login = "jackspirou"
[people.msteinert]
name = "Mike Steinert"
email = ""
login = "msteinert"
[people.nlf]
name = "Nathan LaFreniere"
email = ""
login = "nlf"
[people.tboerger]
name = "Thomas Boerger"
email = "thomas@webhippie.de"
login = "tboerger"
[people.athieriot]
name = "Aurélien Thieriot"
email = "a.thieriot@gmail.com"
login = "athieriot"
[org]
[org.core]
people = [
"bradrydzewski",
"Bugagazavr",
"donny-dont",
"jackspirou",
"msteinert",
"nlf",
"tboerger",
"athieriot"
]

115
Makefile
View File

@ -1,34 +1,107 @@
.PHONY: all clean deps fmt vet test docker
# renovate: datasource=github-releases depName=mvdan/gofumpt
GOFUMPT_PACKAGE_VERSION := v0.6.0
# renovate: datasource=github-releases depName=golangci/golangci-lint
GOLANGCI_LINT_PACKAGE_VERSION := v1.55.2
EXECUTABLE ?= drone-terraform
IMAGE ?= plugins/$(EXECUTABLE)
COMMIT ?= $(shell git rev-parse --short HEAD)
EXECUTABLE := wp-opentofu
LDFLAGS = -X "main.buildCommit=$(COMMIT)"
PACKAGES = $(shell go list ./... | grep -v /vendor/)
DIST := dist
DIST_DIRS := $(DIST)
IMPORT := github.com/thegeeklab/$(EXECUTABLE)
all: deps build test
GO ?= go
CWD ?= $(shell pwd)
PACKAGES ?= $(shell go list ./...)
SOURCES ?= $(shell find . -name "*.go" -type f)
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@$(GOFUMPT_PACKAGE_VERSION)
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_PACKAGE_VERSION)
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GOTESTSUM_PACKAGE ?= gotest.tools/gotestsum@latest
GENERATE ?=
XGO_VERSION := go-1.21.x
XGO_TARGETS ?= linux/amd64,linux/arm64
TARGETOS ?= linux
TARGETARCH ?= amd64
ifneq ("$(TARGETVARIANT)","")
GOARM ?= $(subst v,,$(TARGETVARIANT))
endif
TAGS ?= netgo
ifndef VERSION
ifneq ($(CI_COMMIT_TAG),)
VERSION ?= $(subst v,,$(CI_COMMIT_TAG))
else
VERSION ?= $(shell git rev-parse --short HEAD)
endif
endif
ifndef DATE
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%S%z")
endif
LDFLAGS += -s -w -X "main.BuildVersion=$(VERSION)" -X "main.BuildDate=$(DATE)"
.PHONY: all
all: clean build
.PHONY: clean
clean:
go clean -i ./...
deps:
go get -t ./...
$(GO) clean -i ./...
rm -rf $(DIST_DIRS)
.PHONY: fmt
fmt:
go fmt $(PACKAGES)
$(GO) run $(GOFUMPT_PACKAGE) -extra -w $(SOURCES)
vet:
go vet $(PACKAGES)
.PHONY: golangci-lint
golangci-lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
.PHONY: lint
lint: golangci-lint
.PHONY: generate
generate:
$(GO) generate $(GENERATE)
.PHONY: generate-docs
generate-docs:
$(GO) generate ./cmd/$(EXECUTABLE)/flags.go
.PHONY: test
test:
@for PKG in $(PACKAGES); do go test -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
$(GO) run $(GOTESTSUM_PACKAGE) --no-color=false -- -coverprofile=coverage.out $(PACKAGES)
docker:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-s -w $(LDFLAGS)'
docker build --rm -t $(IMAGE) .
.PHONY: build
build: $(DIST)/$(EXECUTABLE)
$(EXECUTABLE): $(wildcard *.go)
go build -ldflags '-s -w $(LDFLAGS)'
$(DIST)/$(EXECUTABLE): $(SOURCES)
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) GOARM=$(GOARM) $(GO) build -v -tags '$(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -o $@ ./cmd/$(EXECUTABLE)
build: $(EXECUTABLE)
$(DIST_DIRS):
mkdir -p $(DIST_DIRS)
.PHONY: xgo
xgo: | $(DIST_DIRS)
$(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -v -ldflags '-extldflags "-static" $(LDFLAGS)' -tags '$(TAGS)' -targets '$(XGO_TARGETS)' -out $(EXECUTABLE) --pkg cmd/$(EXECUTABLE) .
cp /build/* $(CWD)/$(DIST)
ls -l $(CWD)/$(DIST)
.PHONY: checksum
checksum:
cd $(DIST); $(foreach file,$(wildcard $(DIST)/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
ls -l $(CWD)/$(DIST)
.PHONY: release
release: xgo checksum
.PHONY: deps
deps:
$(GO) mod download
$(GO) install $(GOFUMPT_PACKAGE)
$(GO) install $(GOLANGCI_LINT_PACKAGE)
$(GO) install $(XGO_PACKAGE)
$(GO) install $(GOTESTSUM_PACKAGE)

View File

@ -1,42 +1,21 @@
# drone-terraform
# wp-opentofu
[![Build Status](http://beta.drone.io/api/badges/jmccann/drone-terraform/status.svg)](http://beta.drone.io/jmccann/drone-terraform)
Woodpecker CI plugin to manage infrastructure with OpenTofu
Drone plugin to execute Terraform plan and apply. For the usage information and
a listing of the available options please take a look at [the docs](https://github.com/jmccann/drone-terraform/blob/master/DOCS.md).
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-opentofu/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-opentofu)
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-opentofu)
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-opentofu)
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-opentofu)](https://goreportcard.com/report/github.com/thegeeklab/wp-opentofu)
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/graphs/contributors)
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-opentofu)
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE)
## Build
Woodpecker CI plugin to manage infrastructure with [OpenTofu](https://github.com/opentofu/opentofu). This plugin is a fork of [jmccann/drone-terraform](https://github.com/jmccann/drone-terraform). You can find the full documentation at [https://woodpecker-plugins.geekdocs.de](https://woodpecker-plugins.geekdocs.de/plugins/wp-opentofu).
Build the binary with the following commands:
## Contributors
```
export GO111MODULE=on
go mod download
go test
go build
```
Special thanks to all [contributors](https://github.com/thegeeklab/wp-opentofu/graphs/contributors). If you would like to contribute, please see the [instructions](https://github.com/thegeeklab/wp-opentofu/blob/main/CONTRIBUTING.md).
## Docker
## License
Build the docker image with the following commands:
```
docker build --rm=true \
-t jmccann/drone-terraform \
--build-arg terraform_version=0.12.0 .
```
## Usage
Execute from the working directory:
```
docker run --rm \
-v $(pwd):$(pwd) \
-w $(pwd) \
jmccann/drone-terraform:latest --plan
```
## Drone 0.4
Legacy `drone-terraform` plugin exists @ `jmccann/drone-terraform:0.4`
This project is licensed under the Apache-2.0 License - see the [LICENSE](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE) file for details.

View File

@ -1,40 +0,0 @@
#!/bin/bash
set -e
tag=$1
if [ -z $tag ]; then
echo "please provide a tag arg"
exit 1
fi
major=$(echo $tag | awk -F. '{print $1}')
minor=$(echo $tag | awk -F. '{print $2}')
tf_ver="1.0.2"
echo "Confirm building images for:"
echo " MAJOR: ${major}"
echo " MINOR: ${minor}"
echo " TF_VERSION: ${tf_ver}"
read -p "Proceed? [Y/N] " ans
if [[ "$ans" != "Y" && "$ans" != "y" ]]; then
echo "Cancelling"
exit 0
fi
set -x
docker build -t jmccann/drone-terraform:latest --build-arg terraform_version=${tf_ver} .
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}.${minor}
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}.${minor}-${tf_ver}
docker push jmccann/drone-terraform:latest
docker push jmccann/drone-terraform:${major}
docker push jmccann/drone-terraform:${major}.${minor}
docker push jmccann/drone-terraform:${major}.${minor}-${tf_ver}
set +x

58
cmd/wp-ansible/docs.go Normal file
View File

@ -0,0 +1,58 @@
//go:build generate
// +build generate
package main
import (
"bytes"
"embed"
"fmt"
"os"
"text/template"
"github.com/thegeeklab/wp-opentofu/plugin"
"github.com/thegeeklab/wp-plugin-go/docs"
wp "github.com/thegeeklab/wp-plugin-go/plugin"
wp_template "github.com/thegeeklab/wp-plugin-go/template"
"github.com/urfave/cli/v2"
)
//go:embed templates/docs-data.yaml.tmpl
var yamlTemplate embed.FS
func main() {
settings := &plugin.Settings{}
app := &cli.App{
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
}
out, err := toYAML(app)
if err != nil {
panic(err)
}
fi, err := os.Create("../../docs/data/data-raw.yaml")
if err != nil {
panic(err)
}
defer fi.Close()
if _, err := fi.WriteString(out); err != nil {
panic(err)
}
}
func toYAML(app *cli.App) (string, error) {
var w bytes.Buffer
yamlTmpl, err := template.New("docs").Funcs(wp_template.LoadFuncMap()).ParseFS(yamlTemplate, "templates/docs-data.yaml.tmpl")
if err != nil {
fmt.Println(yamlTmpl)
return "", err
}
if err := yamlTmpl.ExecuteTemplate(&w, "docs-data.yaml.tmpl", docs.GetTemplateData(app)); err != nil {
return "", err
}
return w.String(), nil
}

76
cmd/wp-ansible/flags.go Normal file
View File

@ -0,0 +1,76 @@
package main
import (
"github.com/thegeeklab/wp-opentofu/plugin"
"github.com/urfave/cli/v2"
)
// SettingsFlags has the cli.Flags for the plugin.Settings.
//
//go:generate go run docs.go flags.go
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
return []cli.Flag{
&cli.StringSliceFlag{
Name: "action",
Usage: "tofu actions to execute",
EnvVars: []string{"PLUGIN_ACTION"},
Value: cli.NewStringSlice("validate", "plan", "apply"),
Destination: &settings.Action,
Category: category,
},
&cli.StringFlag{
Name: "init-options",
Usage: "tofu init command options, see https://opentofu.org/docs/cli/commands/init/",
EnvVars: []string{"PLUGIN_INIT_OPTIONS"},
Category: category,
},
&cli.StringFlag{
Name: "fmt-options",
Usage: "options for the fmt command, see https://opentofu.org/docs/cli/commands/fmt/",
EnvVars: []string{"PLUGIN_FMT_OPTIONS"},
Category: category,
},
&cli.IntFlag{
Name: "parallelism",
Usage: "number of concurrent operations",
EnvVars: []string{"PLUGIN_PARALLELISM"},
Category: category,
},
&cli.StringFlag{
Name: "root-dir",
Usage: "root directory where the tofu files live",
EnvVars: []string{"PLUGIN_ROOT_DIR"},
Destination: &settings.RootDir,
Category: category,
},
&cli.BoolFlag{
Name: "no-log",
Usage: "suppress tofu command output",
EnvVars: []string{"PLUGIN_NO_LOG"},
Destination: &settings.NoLog,
Category: category,
},
&cli.StringSliceFlag{
Name: "targets",
Usage: "targets to run `apply` or `plan` action on",
EnvVars: []string{"PLUGIN_TARGETS"},
Destination: &settings.Targets,
Category: category,
},
&cli.StringFlag{
Name: "version",
Usage: "tofu version to use",
EnvVars: []string{"PLUGIN_VERSION"},
Destination: &settings.Version,
Category: category,
},
&cli.BoolFlag{
Name: "refresh",
Usage: "enables refreshing of the state before `plan` and `apply` commands",
EnvVars: []string{"PLUGIN_REFRESH"},
Destination: &settings.Refresh,
Value: true,
Category: category,
},
}
}

28
cmd/wp-ansible/main.go Normal file
View File

@ -0,0 +1,28 @@
package main
import (
"fmt"
"github.com/thegeeklab/wp-opentofu/plugin"
wp "github.com/thegeeklab/wp-plugin-go/plugin"
)
//nolint:gochecknoglobals
var (
BuildVersion = "devel"
BuildDate = "00000000"
)
func main() {
settings := &plugin.Settings{}
options := wp.Options{
Name: "wp-opentofu",
Description: "Manage infrastructure with OpenTofu",
Version: BuildVersion,
VersionMetadata: fmt.Sprintf("date=%s", BuildDate),
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
}
plugin.New(options, settings).Run()
}

View File

@ -0,0 +1,18 @@
---
{{- if .GlobalArgs }}
properties:
{{- range $v := .GlobalArgs }}
- name: {{ $v.Name }}
{{- with $v.Description }}
description: |
{{ . | ToSentence }}
{{- end }}
{{- with $v.Type }}
type: {{ . }}
{{- end }}
{{- with $v.Default }}
defaultValue: {{ . }}
{{- end }}
required: {{ default false $v.Required }}
{{ end -}}
{{ end -}}

59
docs/content/_index.md Normal file
View File

@ -0,0 +1,59 @@
---
title: wp-opentofu
---
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-opentofu/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-opentofu)
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-opentofu)
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-opentofu)
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-opentofu)](https://goreportcard.com/report/github.com/thegeeklab/wp-opentofu)
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/graphs/contributors)
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-opentofu)
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE)
Woodpecker CI plugin to manage infrastructure with [OpenTofu](https://github.com/opentofu/opentofu).
<!-- prettier-ignore-start -->
<!-- spellchecker-disable -->
{{< toc >}}
<!-- spellchecker-enable -->
<!-- prettier-ignore-end -->
## Usage
```YAML
steps:
- name: tofu
image: quay.io/thegeeklab/wp-opentofu
settings:
actions:
- validate
- plan
```
### Parameters
<!-- prettier-ignore-start -->
<!-- spellchecker-disable -->
{{< propertylist name=wp-opentofu.data sort=name >}}
<!-- spellchecker-enable -->
<!-- prettier-ignore-end -->
## Build
Build the binary with the following command:
```Shell
make build
```
Build the Container image with the following command:
```Shell
docker build --file Containerfile.multiarch --tag thegeeklab/wp-opentofu .
```
## Test
```Shell
```

211
docs/data/data.yaml Normal file
View File

@ -0,0 +1,211 @@
---
properties:
- name: become
description: |
Enable privilege escalation.
type: bool
defaultValue: false
required: false
- name: become_method
description: |
Privilege escalation method to use.
type: string
required: false
- name: become_user
description: |
Privilege escalation user to use.
type: string
required: false
- name: check
description: |
Run a check, do not apply any changes.
type: bool
defaultValue: false
required: false
- name: connection
description: |
Connection type to use.
type: string
required: false
- name: diff
description: |
Show the differences. Be careful when using it in public CI environments as it can print secrets.
type: bool
defaultValue: false
required: false
- name: extra_vars
description: |
Set additional variables as `key=value`.
type: list
required: false
- name: flush_cache
description: |
Clear the fact cache for every host in inventory.
type: bool
defaultValue: false
required: false
- name: force_handlers
description: |
Run handlers even if a task fails.
type: bool
defaultValue: false
required: false
- name: forks
description: |
Specify number of parallel processes to use.
type: integer
defaultValue: 5
required: false
- name: galaxy_requirements
description: |
Path to galaxy requirements file.
type: string
required: false
- name: inventory
description: |
Path to inventory file.
type: list
required: false
- name: limit
description: |
Limit selected hosts to an additional pattern.
type: string
required: false
- name: list_hosts
description: |
Outputs a list of matching hosts.
type: bool
defaultValue: false
required: false
- name: list_tags
description: |
List all available tags.
type: bool
defaultValue: false
required: false
- name: list_tasks
description: |
List all tasks that would be executed.
type: bool
defaultValue: false
required: false
- name: module_path
description: |
Prepend paths to module library.
type: list
required: false
- name: playbook
description: |
List of playbooks to apply.
type: list
required: false
- name: private_key
description: |
SSH private key used to authenticate the connection.
type: string
required: false
- name: python_requirements
description: |
Path to python requirements file.
type: string
required: false
- name: scp_extra_args
description: |
Specify extra arguments to pass to SCP connections only.
type: string
required: false
- name: sftp_extra_args
description: |
Specify extra arguments to pass to SFTP connections only.
type: string
required: false
- name: skip_tags
description: |
Only run plays and tasks whose tags do not match.
type: string
required: false
- name: ssh_common_args
description: |
Specify common arguments to pass to SFTP, SCP and SSH connections.
type: string
required: false
- name: ssh_extra_args
description: |
Specify extra arguments to pass to SSH connections only.
type: string
required: false
- name: start_at_task
description: |
Start the playbook at the task matching this name.
type: string
required: false
- name: syntax_check
description: |
Perform a syntax check on the playbook.
type: bool
defaultValue: false
required: false
- name: tags
description: |
Only run plays and tasks tagged with these values.
type: string
required: false
- name: timeout
description: |
Override the connection timeout in seconds.
type: integer
defaultValue: 0
required: false
- name: user
description: |
Connect as this user.
type: string
required: false
- name: vault_id
description: |
The vault identity to use.
type: string
required: false
- name: vault_password
description: |
The vault password to use.
type: string
required: false
- name: verbose
description: |
Level of verbosity, 0 up to 4.
type: integer
defaultValue: 0
required: false

37
go.mod
View File

@ -1,14 +1,31 @@
module github.com/jmccann/drone-terraform
module github.com/thegeeklab/wp-opentofu
go 1.21
require (
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db
github.com/go-ini/ini v1.21.1
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7
github.com/joho/godotenv v1.3.0
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46
golang.org/x/sys v0.0.0-20161006025142-8d1157a43547
github.com/Masterminds/semver/v3 v3.2.1
github.com/thegeeklab/wp-plugin-go v1.5.0
github.com/urfave/cli/v2 v2.27.1
golang.org/x/sys v0.16.0
)
go 1.13
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/rs/zerolog v1.31.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/net v0.19.0 // indirect
)

119
go.sum
View File

@ -1,19 +1,100 @@
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6 h1:Tp6VdyWz8sPuNnRbgf5jqIOV/zoG4mA5nBHtJyFb4Hc=
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U=
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c h1:IF3li2sCc78JFAsluLt9iiCCOnWkMYG9FApcWnq4Sv0=
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k=
github.com/franela/goblin v0.0.0-20170111051028-2fa789fd0c6b h1:pFXMOmYgv60RqCPRU9v+jprPw88/oor7dQDykOfi17A=
github.com/franela/goblin v0.0.0-20170111051028-2fa789fd0c6b/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db h1:gb2Z18BhTPJPpLQWj4T+rfKHYCHxRHCtRxhKKjRidVw=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/go-ini/ini v1.21.1 h1:+QXUYsI7Tfxc64oD6R5BxU/Aq+UwGkyjH4W/hMNG7bg=
github.com/go-ini/ini v1.21.1/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7 h1:SMvOWPJCES2GdFracYbBQh93GXac8fq7HeN6JnpduB8=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v0.0.0-20150907010228-4ed13390c0ac h1:wF2VgtpbaLqhBHV9FxVWzgzgv8VcCjZ66Bl/+F6cpT0=
github.com/joho/godotenv v0.0.0-20150907010228-4ed13390c0ac/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46 h1:EztUvugq7AA7F3lYLmtFQyvKdcY5pisPt10DqPjRCL8=
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
golang.org/x/sys v0.0.0-20161006025142-8d1157a43547/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/thegeeklab/wp-plugin-go v1.5.0 h1:fA/kQwQrntjxdxePKKGecMRnPbj1xwpy6D2JrrPD2qA=
github.com/thegeeklab/wp-plugin-go v1.5.0/go.mod h1:ULBD5SNC7bkIB/UbLMQpcPWj7iZObCTWg8bqXf1zqsA=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,33 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="722.000000pt" height="722.000000pt" viewBox="0 0 722.000000 722.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.13, written by Peter Selinger 2001-2015
</metadata>
<g transform="translate(0.000000,722.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3769 7206 c-3 -3 -221 -32 -484 -65 -264 -33 -496 -62 -515 -64 -19
-3 -159 -43 -310 -89 -195 -59 -291 -93 -330 -117 -306 -190 -812 -498 -836
-510 -22 -11 -57 -54 -111 -136 -44 -66 -236 -358 -428 -650 -191 -291 -359
-541 -372 -556 -12 -14 -23 -31 -23 -39 0 -17 -319 -1119 -330 -1140 -5 -9 -9
-119 -10 -245 l-1 -230 121 -535 c121 -532 122 -536 186 -678 35 -78 64 -148
64 -155 0 -7 94 -168 208 -359 l209 -346 251 -237 c246 -231 254 -237 359
-289 60 -29 423 -206 808 -393 l700 -340 245 -12 c135 -7 382 -12 549 -12
l305 0 285 53 285 53 760 437 c419 240 766 441 771 446 6 5 218 342 470 748
l460 739 81 435 c45 239 81 437 79 440 -2 3 -37 280 -80 615 -42 336 -81 618
-86 628 -15 28 -195 547 -204 587 -4 19 -15 44 -25 55 -18 21 -405 570 -436
621 -11 16 -84 92 -164 169 -80 76 -215 208 -301 292 -86 84 -161 153 -166
153 -6 0 -271 124 -589 276 -319 152 -601 286 -629 299 -32 15 -169 46 -380
85 -410 78 -379 73 -386 66z m-1526 -2150 l567 -319 0 -668 c0 -368 -3 -669
-6 -669 -3 0 -273 150 -600 333 l-594 332 0 673 0 674 33 -19 c17 -11 287
-162 600 -337z m1273 -718 l594 -333 0 -673 0 -674 -42 24 c-24 13 -294 165
-600 337 l-558 313 0 669 c0 368 3 669 6 669 3 0 273 -150 600 -332z m1892
-339 l-3 -671 -595 -334 -595 -334 -3 667 c-1 430 1 670 8 677 12 12 1172 665
1183 666 4 0 6 -302 5 -671z m-1892 -1121 l593 -333 1 -672 c0 -370 -1 -673
-3 -673 -2 0 -271 150 -598 334 l-594 334 -3 671 c-1 369 1 671 4 671 4 0 273
-150 600 -332z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

184
main.go
View File

@ -1,184 +0,0 @@
package main
import (
"encoding/json"
"os"
"github.com/Sirupsen/logrus"
"github.com/joho/godotenv"
"github.com/urfave/cli"
)
var revision string // build number set at compile-time
func main() {
app := cli.NewApp()
app.Name = "terraform plugin"
app.Usage = "terraform plugin"
app.Action = run
app.Version = revision
app.Flags = []cli.Flag{
//
// plugin args
//
cli.StringSliceFlag{
Name: "actions",
Usage: "a list of actions to have terraform perform",
EnvVar: "PLUGIN_ACTIONS",
Value: &cli.StringSlice{"validate", "plan", "apply"},
},
cli.StringFlag{
Name: "ca_cert",
Usage: "ca cert to add to your environment to allow terraform to use internal/private resources",
EnvVar: "PLUGIN_CA_CERT",
},
cli.StringFlag{
Name: "env_file",
Usage: "pass filename to source it and load variables into current shell",
EnvVar: "PLUGIN_ENV_FILE",
},
cli.StringFlag{
Name: "init_options",
Usage: "options for the init command. See https://www.terraform.io/docs/commands/init.html",
EnvVar: "PLUGIN_INIT_OPTIONS",
},
cli.StringFlag{
Name: "fmt_options",
Usage: "options for the fmt command. See https://www.terraform.io/docs/commands/fmt.html",
EnvVar: "PLUGIN_FMT_OPTIONS",
},
cli.IntFlag{
Name: "parallelism",
Usage: "The number of concurrent operations as Terraform walks its graph",
EnvVar: "PLUGIN_PARALLELISM",
},
cli.StringFlag{
Name: "netrc.machine",
Usage: "netrc machine",
EnvVar: "DRONE_NETRC_MACHINE",
},
cli.StringFlag{
Name: "netrc.username",
Usage: "netrc username",
EnvVar: "DRONE_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc.password",
Usage: "netrc password",
EnvVar: "DRONE_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "role_arn_to_assume",
Usage: "A role to assume before running the terraform commands",
EnvVar: "PLUGIN_ROLE_ARN_TO_ASSUME",
},
cli.StringFlag{
Name: "root_dir",
Usage: "The root directory where the terraform files live. When unset, the top level directory will be assumed",
EnvVar: "PLUGIN_ROOT_DIR",
},
cli.StringFlag{
Name: "secrets",
Usage: "a map of secrets to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `<key>=<ENV>` option",
EnvVar: "PLUGIN_SECRETS",
},
cli.BoolFlag{
Name: "sensitive",
Usage: "whether or not to suppress terraform commands to stdout",
EnvVar: "PLUGIN_SENSITIVE",
},
cli.StringSliceFlag{
Name: "targets",
Usage: "targets to run apply or plan on",
EnvVar: "PLUGIN_TARGETS",
},
cli.StringFlag{
Name: "tf.version",
Usage: "terraform version to use",
EnvVar: "PLUGIN_TF_VERSION",
},
cli.StringFlag{
Name: "vars",
Usage: "a map of variables to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `<key>=<value>` option",
EnvVar: "PLUGIN_VARS",
},
cli.StringSliceFlag{
Name: "var_files",
Usage: "a list of var files to use. Each value is passed as -var-file=<value>",
EnvVar: "PLUGIN_VAR_FILES",
},
cli.StringFlag{
Name: "tf_data_dir",
Usage: "changes the location where Terraform keeps its per-working-directory data, such as the current remote backend configuration",
EnvVar: "PLUGIN_TF_DATA_DIR",
},
cli.BoolFlag{
Name: "disable_refresh",
Usage: "whether or not to disable refreshing state before `plan` and `apply` commands",
EnvVar: "PLUGIN_DISABLE_REFRESH",
},
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
func run(c *cli.Context) error {
logrus.WithFields(logrus.Fields{
"Revision": revision,
}).Info("Drone Terraform Plugin Version")
if c.String("env_file") != "" {
_ = godotenv.Load(c.String("env_file"))
}
var vars map[string]string
if c.String("vars") != "" {
if err := json.Unmarshal([]byte(c.String("vars")), &vars); err != nil {
panic(err)
}
}
var secrets map[string]string
if c.String("secrets") != "" {
if err := json.Unmarshal([]byte(c.String("secrets")), &secrets); err != nil {
panic(err)
}
}
initOptions := InitOptions{}
json.Unmarshal([]byte(c.String("init_options")), &initOptions)
fmtOptions := FmtOptions{}
json.Unmarshal([]byte(c.String("fmt_options")), &fmtOptions)
plugin := Plugin{
Config: Config{
Actions: c.StringSlice("actions"),
Vars: vars,
Secrets: secrets,
InitOptions: initOptions,
FmtOptions: fmtOptions,
Cacert: c.String("ca_cert"),
Sensitive: c.Bool("sensitive"),
RoleARN: c.String("role_arn_to_assume"),
RootDir: c.String("root_dir"),
Parallelism: c.Int("parallelism"),
Targets: c.StringSlice("targets"),
VarFiles: c.StringSlice("var_files"),
TerraformDataDir: c.String("tf_data_dir"),
DisableRefresh: c.Bool("disable_refresh"),
},
Netrc: Netrc{
Login: c.String("netrc.username"),
Machine: c.String("netrc.machine"),
Password: c.String("netrc.password"),
},
Terraform: Terraform{
Version: c.String("tf.version"),
},
}
return plugin.Exec()
}

415
plugin.go
View File

@ -1,415 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"os/user"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
)
type (
// Config holds input parameters for the plugin
Config struct {
Actions []string
Vars map[string]string
Secrets map[string]string
InitOptions InitOptions
FmtOptions FmtOptions
Cacert string
Sensitive bool
RoleARN string
RootDir string
Parallelism int
Targets []string
VarFiles []string
TerraformDataDir string
DisableRefresh bool
}
// Netrc is credentials for cloning
Netrc struct {
Machine string
Login string
Password string
}
// InitOptions include options for the Terraform's init command
InitOptions struct {
BackendConfig []string `json:"backend-config"`
Lock *bool `json:"lock"`
LockTimeout string `json:"lock-timeout"`
}
// FmtOptions fmt options for the Terraform's fmt command
FmtOptions struct {
List *bool `json:"list"`
Write *bool `json:"write"`
Diff *bool `json:"diff"`
Check *bool `json:"check"`
}
// Plugin represents the plugin instance to be executed
Plugin struct {
Config Config
Netrc Netrc
Terraform Terraform
}
)
// Exec executes the plugin
func (p Plugin) Exec() error {
// Install specified version of terraform
if p.Terraform.Version != "" {
err := installTerraform(p.Terraform.Version)
if err != nil {
return err
}
}
if p.Config.RoleARN != "" && !credsSet() {
assumeRole(p.Config.RoleARN)
}
// writing the .netrc file with Github credentials in it.
err := writeNetrc(p.Netrc.Machine, p.Netrc.Login, p.Netrc.Password)
if err != nil {
return err
}
terraformDataDir := ".terraform"
if p.Config.TerraformDataDir != "" {
terraformDataDir = p.Config.TerraformDataDir
os.Setenv("TF_DATA_DIR", p.Config.TerraformDataDir)
}
var commands []*exec.Cmd
commands = append(commands, exec.Command("terraform", "version"))
CopyTfEnv()
if p.Config.Cacert != "" {
commands = append(commands, installCaCert(p.Config.Cacert))
}
commands = append(commands, deleteCache(terraformDataDir))
commands = append(commands, initCommand(p.Config.InitOptions))
commands = append(commands, getModules())
// Add commands listed from Actions
for _, action := range p.Config.Actions {
switch action {
case "fmt":
commands = append(commands, tfFmt(p.Config))
case "validate":
commands = append(commands, tfValidate())
case "plan":
commands = append(commands, tfPlan(p.Config, false))
case "plan-destroy":
commands = append(commands, tfPlan(p.Config, true))
case "apply":
commands = append(commands, tfApply(p.Config))
case "destroy":
commands = append(commands, tfDestroy(p.Config))
default:
return fmt.Errorf("valid actions are: fmt, validate, plan, apply, plan-destroy, destroy. You provided %s", action)
}
}
commands = append(commands, deleteCache(terraformDataDir))
for _, c := range commands {
if c.Dir == "" {
wd, err := os.Getwd()
if err == nil {
c.Dir = wd
}
}
if p.Config.RootDir != "" {
c.Dir = c.Dir + "/" + p.Config.RootDir
}
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if !p.Config.Sensitive {
trace(c)
}
err := c.Run()
if err != nil {
logrus.WithFields(logrus.Fields{
"error": err,
}).Fatal("Failed to execute a command")
}
logrus.Debug("Command completed successfully")
}
return nil
}
// CopyTfEnv creates copies of TF_VAR_ to lowercase
func CopyTfEnv() {
tfVar := regexp.MustCompile(`^TF_VAR_.*$`)
for _, e := range os.Environ() {
pair := strings.SplitN(e, "=", 2)
if tfVar.MatchString(pair[0]) {
name := strings.Split(pair[0], "TF_VAR_")
os.Setenv(fmt.Sprintf("TF_VAR_%s", strings.ToLower(name[1])), pair[1])
}
}
}
func credsSet() bool {
awsTokens := []string{"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"}
for _, token := range awsTokens {
if os.Getenv(token) == "" {
return false
}
}
return true
}
func assumeRole(roleArn string) {
client := sts.New(session.New())
duration := time.Hour * 1
stsProvider := &stscreds.AssumeRoleProvider{
Client: client,
Duration: duration,
RoleARN: roleArn,
RoleSessionName: "drone",
}
value, err := credentials.NewCredentials(stsProvider).Get()
if err != nil {
logrus.WithFields(logrus.Fields{
"error": err,
}).Fatal("Error assuming role!")
}
os.Setenv("AWS_ACCESS_KEY_ID", value.AccessKeyID)
os.Setenv("AWS_SECRET_ACCESS_KEY", value.SecretAccessKey)
os.Setenv("AWS_SESSION_TOKEN", value.SessionToken)
}
func deleteCache(terraformDataDir string) *exec.Cmd {
return exec.Command(
"rm",
"-rf",
terraformDataDir,
)
}
func getModules() *exec.Cmd {
return exec.Command(
"terraform",
"get",
)
}
func initCommand(config InitOptions) *exec.Cmd {
args := []string{
"init",
}
for _, v := range config.BackendConfig {
args = append(args, fmt.Sprintf("-backend-config=%s", v))
}
// Fail Terraform execution on prompt
args = append(args, "-input=false")
return exec.Command(
"terraform",
args...,
)
}
func installCaCert(cacert string) *exec.Cmd {
ioutil.WriteFile("/usr/local/share/ca-certificates/ca_cert.crt", []byte(cacert), 0644)
return exec.Command(
"update-ca-certificates",
)
}
func trace(cmd *exec.Cmd) {
fmt.Println("$", strings.Join(cmd.Args, " "))
}
func tfApply(config Config) *exec.Cmd {
args := []string{
"apply",
}
for _, v := range config.Targets {
args = append(args, "--target", fmt.Sprintf("%s", v))
}
if config.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
}
if config.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
}
if config.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
}
if config.DisableRefresh {
args = append(args, "-refresh=false")
}
args = append(args, getTfoutPath())
return exec.Command(
"terraform",
args...,
)
}
func tfDestroy(config Config) *exec.Cmd {
args := []string{
"destroy",
}
for _, v := range config.Targets {
args = append(args, fmt.Sprintf("-target=%s", v))
}
args = append(args, varFiles(config.VarFiles)...)
args = append(args, vars(config.Vars)...)
if config.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
}
if config.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
}
if config.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
}
args = append(args, "-auto-approve")
return exec.Command(
"terraform",
args...,
)
}
func tfPlan(config Config, destroy bool) *exec.Cmd {
args := []string{
"plan",
}
if destroy {
args = append(args, "-destroy")
} else {
args = append(args, fmt.Sprintf("-out=%s", getTfoutPath()))
}
for _, v := range config.Targets {
args = append(args, "--target", fmt.Sprintf("%s", v))
}
args = append(args, varFiles(config.VarFiles)...)
args = append(args, vars(config.Vars)...)
if config.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
}
if config.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
}
if config.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
}
if config.DisableRefresh {
args = append(args, "-refresh=false")
}
return exec.Command(
"terraform",
args...,
)
}
func tfValidate() *exec.Cmd {
return exec.Command(
"terraform",
"validate",
)
}
func tfFmt(config Config) *exec.Cmd {
args := []string{
"fmt",
}
if config.FmtOptions.List != nil {
args = append(args, fmt.Sprintf("-list=%t", *config.FmtOptions.List))
}
if config.FmtOptions.Write != nil {
args = append(args, fmt.Sprintf("-write=%t", *config.FmtOptions.Write))
}
if config.FmtOptions.Diff != nil {
args = append(args, fmt.Sprintf("-diff=%t", *config.FmtOptions.Diff))
}
if config.FmtOptions.Check != nil {
args = append(args, fmt.Sprintf("-check=%t", *config.FmtOptions.Check))
}
return exec.Command(
"terraform",
args...,
)
}
func getTfoutPath() string {
terraformDataDir := os.Getenv("TF_DATA_DIR")
if terraformDataDir == ".terraform" || terraformDataDir == "" {
return "plan.tfout"
}
return fmt.Sprintf("%s.plan.tfout", terraformDataDir)
}
func vars(vs map[string]string) []string {
var args []string
for k, v := range vs {
args = append(args, "-var", fmt.Sprintf("%s=%s", k, v))
}
return args
}
func varFiles(vfs []string) []string {
var args []string
for _, v := range vfs {
args = append(args, fmt.Sprintf("-var-file=%s", v))
}
return args
}
// helper function to write a netrc file.
// The following code comes from the official Git plugin for Drone:
// https://github.com/drone-plugins/drone-git/blob/8386effd2fe8c8695cf979427f8e1762bd805192/utils.go#L43-L68
func writeNetrc(machine, login, password string) error {
if machine == "" {
return nil
}
out := fmt.Sprintf(
netrcFile,
machine,
login,
password,
)
home := "/root"
u, err := user.Current()
if err == nil {
home = u.HomeDir
}
path := filepath.Join(home, ".netrc")
return ioutil.WriteFile(path, []byte(out), 0600)
}
const netrcFile = `
machine %s
login %s
password %s
`

112
plugin/impl.go Normal file
View File

@ -0,0 +1,112 @@
package plugin
import (
"context"
"errors"
"fmt"
"os"
"github.com/thegeeklab/wp-plugin-go/trace"
"golang.org/x/sys/execabs"
)
var (
ErrTaintedPath = errors.New("filepath is tainted")
ErrMaxSizeSizeLimit = errors.New("max size limit of decoded data exceeded")
ErrActionUnknown = errors.New("action not found")
ErrInvalidVersion = errors.New("invalid version string")
)
const (
maxDecompressionSize = 1024
defaultDirPerm = 0o755
)
//nolint:revive
func (p *Plugin) run(ctx context.Context) error {
if err := p.Validate(); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := p.Execute(); err != nil {
return fmt.Errorf("execution failed: %w", err)
}
return nil
}
// Validate handles the settings validation of the plugin.
func (p *Plugin) Validate() error {
p.Settings.DataDir = ".terraform"
if value, ok := os.LookupEnv("TF_DATA_DIR"); ok {
p.Settings.DataDir = value
}
p.Settings.OutFile = "plan.tfout"
if p.Settings.DataDir == ".terraform" {
p.Settings.OutFile = fmt.Sprintf("%s.plan.tfout", p.Settings.DataDir)
}
if p.Settings.Version != "" {
err := installPackage(p.Plugin.Network.Context, p.Plugin.Network.Client, p.Settings.Version, maxDecompressionSize)
if err != nil {
return err
}
}
return nil
}
// Execute provides the implementation of the plugin.
func (p *Plugin) Execute() error {
commands := []*execabs.Cmd{
p.versionCommand(),
}
commands = append(commands, p.initCommand())
commands = append(commands, p.getModulesCommand())
for _, action := range p.Settings.Action.Value() {
switch action {
case "fmt":
commands = append(commands, p.fmtCommand())
case "validate":
commands = append(commands, p.validateCommand())
case "plan":
commands = append(commands, p.planCommand(false))
case "plan-destroy":
commands = append(commands, p.planCommand(true))
case "apply":
commands = append(commands, p.applyCommand())
case "destroy":
commands = append(commands, p.destroyCommand())
default:
return fmt.Errorf("%w: %s", ErrActionUnknown, action)
}
}
if err := deleteCache(p.Settings.DataDir); err != nil {
return err
}
for _, cmd := range commands {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if p.Settings.RootDir != "" {
cmd.Dir = p.Settings.RootDir
}
cmd.Env = os.Environ()
if !p.Settings.NoLog {
trace.Cmd(cmd)
}
if err := cmd.Run(); err != nil {
return err
}
}
return deleteCache(p.Settings.DataDir)
}

57
plugin/plugin.go Normal file
View File

@ -0,0 +1,57 @@
package plugin
import (
wp "github.com/thegeeklab/wp-plugin-go/plugin"
"github.com/urfave/cli/v2"
)
// Plugin implements provide the plugin.
type Plugin struct {
*wp.Plugin
Settings *Settings
}
// Settings for the Plugin.
type Settings struct {
Action cli.StringSlice
Version string
InitOptions InitOptions
FmtOptions FmtOptions
RootDir string
DataDir string
OutFile string
Parallelism int
Targets cli.StringSlice
Refresh bool
NoLog bool
}
// InitOptions include options for the OpenTofu init command.
type InitOptions struct {
BackendConfig []string `json:"backend-config"`
Lock *bool `json:"lock"`
LockTimeout string `json:"lock-timeout"`
}
// FmtOptions fmt options for the OpenTofu fmt command.
type FmtOptions struct {
List *bool `json:"list"`
Write *bool `json:"write"`
Diff *bool `json:"diff"`
Check *bool `json:"check"`
}
func New(options wp.Options, settings *Settings) *Plugin {
p := &Plugin{}
if options.Execute == nil {
options.Execute = p.run
}
p.Plugin = wp.New(options)
p.Settings = settings
return p
}

180
plugin/tofu.go Normal file
View File

@ -0,0 +1,180 @@
package plugin
import (
"fmt"
"golang.org/x/sys/execabs"
)
const (
tofuBin = "/usr/local/bin/tofu"
)
func (p *Plugin) versionCommand() *execabs.Cmd {
args := []string{
"version",
}
return execabs.Command(
tofuBin,
args...,
)
}
func (p *Plugin) initCommand() *execabs.Cmd {
args := []string{
"init",
}
for _, v := range p.Settings.InitOptions.BackendConfig {
args = append(args, fmt.Sprintf("-backend-config=%s", v))
}
// Fail tofu execution on prompt
args = append(args, "-input=false")
return execabs.Command(
tofuBin,
args...,
)
}
func (p *Plugin) getModulesCommand() *execabs.Cmd {
return execabs.Command(
tofuBin,
"get",
)
}
func (p *Plugin) validateCommand() *execabs.Cmd {
return execabs.Command(
tofuBin,
"validate",
)
}
func (p *Plugin) fmtCommand() *execabs.Cmd {
args := []string{
"fmt",
}
if p.Settings.FmtOptions.List != nil {
args = append(args, fmt.Sprintf("-list=%t", *p.Settings.FmtOptions.List))
}
if p.Settings.FmtOptions.Write != nil {
args = append(args, fmt.Sprintf("-write=%t", *p.Settings.FmtOptions.Write))
}
if p.Settings.FmtOptions.Diff != nil {
args = append(args, fmt.Sprintf("-diff=%t", *p.Settings.FmtOptions.Diff))
}
if p.Settings.FmtOptions.Check != nil {
args = append(args, fmt.Sprintf("-check=%t", *p.Settings.FmtOptions.Check))
}
return execabs.Command(
tofuBin,
args...,
)
}
func (p *Plugin) planCommand(destroy bool) *execabs.Cmd {
args := []string{
"plan",
}
if destroy {
args = append(args, "-destroy")
} else {
args = append(args, fmt.Sprintf("-out=%s", p.Settings.OutFile))
}
for _, value := range p.Settings.Targets.Value() {
args = append(args, "--target", value)
}
if p.Settings.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
}
if p.Settings.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
}
if p.Settings.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
}
if !p.Settings.Refresh {
args = append(args, "-refresh=false")
}
return execabs.Command(
tofuBin,
args...,
)
}
func (p *Plugin) applyCommand() *execabs.Cmd {
args := []string{
"apply",
}
for _, v := range p.Settings.Targets.Value() {
args = append(args, "--target", v)
}
if p.Settings.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
}
if p.Settings.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
}
if p.Settings.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
}
if !p.Settings.Refresh {
args = append(args, "-refresh=false")
}
args = append(args, p.Settings.OutFile)
return execabs.Command(
tofuBin,
args...,
)
}
func (p *Plugin) destroyCommand() *execabs.Cmd {
args := []string{
"destroy",
}
for _, v := range p.Settings.Targets.Value() {
args = append(args, fmt.Sprintf("-target=%s", v))
}
if p.Settings.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
}
if p.Settings.InitOptions.Lock != nil {
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
}
if p.Settings.InitOptions.LockTimeout != "" {
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
}
args = append(args, "-auto-approve")
return execabs.Command(
tofuBin,
args...,
)
}

151
plugin/utils.go Normal file
View File

@ -0,0 +1,151 @@
package plugin
import (
"archive/zip"
"context"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/Masterminds/semver/v3"
)
func installPackage(ctx context.Context, client *http.Client, version string, maxSize int64) error {
// Sanitize user input
if _, err := semver.NewVersion(version); err != nil {
return fmt.Errorf("%w: %v", ErrInvalidVersion, version)
}
err := downloadPackage(
ctx,
client,
"/tmp/tofu.zip",
fmt.Sprintf(
"https://github.com/opentofu/opentofu/releases/download/%s/tofu_%s_linux_amd64.zip",
version,
strings.TrimPrefix(version, ""),
),
)
if err != nil {
return err
}
return unzip("/tmp/tofu.zip", "/bin", maxSize)
}
func downloadPackage(ctx context.Context, client *http.Client, filepath, url string) error {
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Get the data
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// Writer the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
func unzip(src, dest string, maxSize int64) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func() {
if err := r.Close(); err != nil {
panic(err)
}
}()
_ = os.MkdirAll(dest, defaultDirPerm)
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
}
}()
path, err := sanitizeArchivePath(dest, f.Name)
if err != nil {
return err
}
if f.FileInfo().IsDir() { //nolint: nestif
_ = os.MkdirAll(path, f.Mode())
} else {
_ = os.MkdirAll(filepath.Dir(path), f.Mode())
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
written, err := io.CopyN(f, rc, maxSize)
if err != nil {
return err
} else if written == maxSize {
return fmt.Errorf("%w: %d", ErrMaxSizeSizeLimit, maxSize)
}
}
return nil
}
for _, f := range r.File {
err := extractAndWriteFile(f)
if err != nil {
return err
}
}
return nil
}
func sanitizeArchivePath(d, t string) (string, error) {
value := filepath.Join(d, t)
if strings.HasPrefix(value, filepath.Clean(d)) {
return value, nil
}
return "", fmt.Errorf("%w: %v", ErrTaintedPath, t)
}
func deleteCache(path string) error {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil
}
return os.Remove(path)
}

View File

@ -1,301 +0,0 @@
package main
import (
"os"
"os/exec"
"testing"
. "github.com/franela/goblin"
)
func TestPlugin(t *testing.T) {
g := Goblin(t)
g.Describe("CopyTfEnv", func() {
g.It("Should create copies of TF_VAR_ to lowercase", func() {
// Set some initial TF_VAR_ that are uppercase
os.Setenv("TF_VAR_SOMETHING", "some value")
os.Setenv("TF_VAR_SOMETHING_ELSE", "some other value")
os.Setenv("TF_VAR_BASE64", "dGVzdA==")
CopyTfEnv()
// Make sure new env vars exist with proper values
g.Assert(os.Getenv("TF_VAR_something")).Equal("some value")
g.Assert(os.Getenv("TF_VAR_something_else")).Equal("some other value")
g.Assert(os.Getenv("TF_VAR_base64")).Equal("dGVzdA==")
})
})
g.Describe("credsSet", func() {
tests := []struct {
name string
args map[string]string
want bool
}{
{
"Should return true when all credentials were set",
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SECRET_ACCESS_KEY": "x", "AWS_SESSION_TOKEN": "x"},
true,
},
{
"Should return false when access key id is missing",
map[string]string{"AWS_SECRET_ACCESS_KEY": "x", "AWS_SESSION_TOKEN": "x"},
false,
},
{
"Should return false when secret access key is missing",
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SESSION_TOKEN": "x"},
false,
},
{
"Should return false when session token is missing",
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SECRET_ACCESS_KEY": "x"},
false,
},
}
for _, tt := range tests {
g.It(tt.name, func() {
for k, v := range tt.args {
os.Setenv(k, v)
}
g.Assert(credsSet()).Equal(tt.want)
})
}
})
g.Describe("tfApply", func() {
g.It("Should return correct apply commands given the arguments", func() {
type args struct {
config Config
}
tests := []struct {
name string
args args
want *exec.Cmd
}{
{
"default",
args{config: Config{}},
exec.Command("terraform", "apply", "plan.tfout"),
},
{
"with parallelism",
args{config: Config{Parallelism: 5}},
exec.Command("terraform", "apply", "-parallelism=5", "plan.tfout"),
},
{
"with targets",
args{config: Config{Targets: []string{"target1", "target2"}}},
exec.Command("terraform", "apply", "--target", "target1", "--target", "target2", "plan.tfout"),
},
}
for _, tt := range tests {
g.Assert(tfApply(tt.args.config).Args).Equal(tt.want.Args)
}
})
})
g.Describe("tfDestroy", func() {
g.It("Should return correct destroy commands given the arguments", func() {
type args struct {
config Config
}
tests := []struct {
name string
args args
want *exec.Cmd
}{
{
"default",
args{config: Config{}},
exec.Command("terraform", "destroy", "-auto-approve"),
},
{
"with parallelism",
args{config: Config{Parallelism: 5}},
exec.Command("terraform", "destroy", "-parallelism=5", "-auto-approve"),
},
{
"with targets",
args{config: Config{Targets: []string{"target1", "target2"}}},
exec.Command("terraform", "destroy", "-target=target1", "-target=target2", "-auto-approve"),
},
{
"with vars",
args{config: Config{Vars: map[string]string{"username": "someuser", "password": "1pass"}}},
exec.Command("terraform", "destroy", "-var", "username=someuser", "-var", "password=1pass", "-auto-approve"),
},
{
"with var-files",
args{config: Config{VarFiles: []string{"common.tfvars", "prod.tfvars"}}},
exec.Command("terraform", "destroy", "-var-file=common.tfvars", "-var-file=prod.tfvars", "-auto-approve"),
},
}
for _, tt := range tests {
g.Assert(tfDestroy(tt.args.config)).Equal(tt.want)
}
})
})
g.Describe("tfValidate", func() {
g.It("Should return correct validate command", func() {
tests := []struct {
name string
want *exec.Cmd
}{
{
"default",
exec.Command("terraform", "validate"),
},
}
for _, tt := range tests {
g.Assert(tfValidate()).Equal(tt.want)
}
})
})
g.Describe("tfPlan", func() {
g.It("Should return correct plan commands given the arguments", func() {
type args struct {
config Config
}
tests := []struct {
name string
args args
destroy bool
want *exec.Cmd
}{
{
"default",
args{config: Config{}},
false,
exec.Command("terraform", "plan", "-out=plan.tfout"),
},
{
"destroy",
args{config: Config{}},
true,
exec.Command("terraform", "plan", "-destroy"),
},
{
"with vars",
args{config: Config{Vars: map[string]string{"username": "someuser", "password": "1pass"}}},
false,
exec.Command("terraform", "plan", "-out=plan.tfout", "-var", "username=someuser", "-var", "password=1pass"),
},
{
"with var-files",
args{config: Config{VarFiles: []string{"common.tfvars", "prod.tfvars"}}},
false,
exec.Command("terraform", "plan", "-out=plan.tfout", "-var-file=common.tfvars", "-var-file=prod.tfvars"),
},
}
for _, tt := range tests {
g.Assert(tfPlan(tt.args.config, tt.destroy)).Equal(tt.want)
}
})
})
g.Describe("tfFmt", func() {
g.It("Should return correct fmt commands given the arguments", func() {
type args struct {
config Config
}
affirmative := true
negative := false
tests := []struct {
name string
args args
want *exec.Cmd
}{
{
"default",
args{config: Config{}},
exec.Command("terraform", "fmt"),
},
{
"with list",
args{config: Config{FmtOptions: FmtOptions{List: &affirmative}}},
exec.Command("terraform", "fmt", "-list=true"),
},
{
"with write",
args{config: Config{FmtOptions: FmtOptions{Write: &affirmative}}},
exec.Command("terraform", "fmt", "-write=true"),
},
{
"with diff",
args{config: Config{FmtOptions: FmtOptions{Diff: &affirmative}}},
exec.Command("terraform", "fmt", "-diff=true"),
},
{
"with check",
args{config: Config{FmtOptions: FmtOptions{Check: &affirmative}}},
exec.Command("terraform", "fmt", "-check=true"),
},
{
"with combination",
args{config: Config{FmtOptions: FmtOptions{
List: &negative,
Write: &negative,
Diff: &affirmative,
Check: &affirmative,
}}},
exec.Command("terraform", "fmt", "-list=false", "-write=false", "-diff=true", "-check=true"),
},
}
for _, tt := range tests {
g.Assert(tfFmt(tt.args.config)).Equal(tt.want)
}
})
})
g.Describe("tfDataDir", func() {
g.It("Should override the terraform data dir environment variable when provided", func() {
type args struct {
config Config
}
tests := []struct {
name string
args args
want *exec.Cmd
}{
{
"with TerraformDataDir",
args{config: Config{TerraformDataDir: ".overriden_terraform_dir"}},
exec.Command("terraform", "apply", ".overriden_terraform_dir.plan.tfout"),
},
{
"with TerraformDataDir value as .terraform",
args{config: Config{TerraformDataDir: ".terraform"}},
exec.Command("terraform", "apply", "plan.tfout"),
},
{
"without TerraformDataDir",
args{config: Config{}},
exec.Command("terraform", "apply", "plan.tfout"),
},
}
for _, tt := range tests {
os.Setenv("TF_DATA_DIR", tt.args.config.TerraformDataDir)
applied := tfApply(tt.args.config)
g.Assert(applied).Equal(tt.want)
}
})
})
}

4
renovate.json Normal file
View File

@ -0,0 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>thegeeklab/renovate-presets:golang"]
}

View File

@ -1,114 +0,0 @@
package main
import (
"archive/zip"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
)
type (
// Terraform holds input parameters for terraform
Terraform struct {
Version string
}
)
func installTerraform(version string) error {
err := downloadTerraform(version)
if err != nil {
return nil
}
return Unzip("/var/tmp/terraform.zip", "/bin")
}
func downloadTerraform(version string) error {
return downloadFile("/var/tmp/terraform.zip", fmt.Sprintf("https://releases.hashicorp.com/terraform/%s/terraform_%s_linux_amd64.zip", version, version))
}
func downloadFile(filepath string, url string) error {
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Writer the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
// Unzip a file to a destination
func Unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func() {
if err := r.Close(); err != nil {
panic(err)
}
}()
os.MkdirAll(dest, 0755)
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
}
}()
path := filepath.Join(dest, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
os.MkdirAll(filepath.Dir(path), f.Mode())
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
return nil
}
for _, f := range r.File {
err := extractAndWriteFile(f)
if err != nil {
return err
}
}
return nil
}