├── .github └── workflows │ ├── golangci-lint.yml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── Makefile ├── README.md ├── cmd └── mmbuild │ └── main.go ├── docs ├── builds.HOWTO.md ├── provenance.md └── storage.md ├── examples ├── server │ ├── Makefile │ ├── matterbuild.yaml │ └── release.mk └── webapp │ ├── README.md │ └── matterbuild.yaml ├── go.mod └── go.sum /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | pull_request: 4 | jobs: 5 | golangci: 6 | name: lint 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: golangci-lint 11 | uses: golangci/golangci-lint-action@v2 12 | with: 13 | version: v1.42 14 | # Optional: show only new issues if it's a pull request. The default value is `false`. 15 | # only-new-issues: true -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | go-version: [1.16.x, 1.17.x] 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | steps: 18 | - name: Install Go 19 | uses: actions/setup-go@v2 20 | with: 21 | go-version: ${{ matrix.go-version }} 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | - name: Test 25 | run: go test ./... 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .vscode 17 | tmp 18 | 19 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | run: 3 | concurrency: 6 4 | deadline: 5m 5 | issues: 6 | exclude-rules: 7 | # counterfeiter fakes are usually named 'fake_.go' 8 | - path: fake_.*\.go 9 | linters: 10 | - gocritic 11 | - golint 12 | - dupl 13 | 14 | # Maximum issues count per one linter. Set to 0 to disable. Default is 50. 15 | max-issues-per-linter: 0 16 | 17 | # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. 18 | max-same-issues: 0 19 | linters: 20 | disable-all: true 21 | enable: 22 | - asciicheck 23 | - bodyclose 24 | - deadcode 25 | - depguard 26 | - dogsled 27 | - dupl 28 | - durationcheck 29 | - errcheck 30 | - goconst 31 | - gocritic 32 | - gocyclo 33 | - godox 34 | - gofmt 35 | - gofumpt 36 | - goheader 37 | - goimports 38 | - gomoddirectives 39 | - gomodguard 40 | - goprintffuncname 41 | - gosec 42 | - gosimple 43 | - govet 44 | - importas 45 | - ineffassign 46 | - makezero 47 | - misspell 48 | - nakedret 49 | - nolintlint 50 | - prealloc 51 | - predeclared 52 | - promlinter 53 | - revive 54 | - rowserrcheck 55 | - sqlclosecheck 56 | - staticcheck 57 | - structcheck 58 | - stylecheck 59 | - typecheck 60 | - unconvert 61 | - unparam 62 | - unused 63 | - varcheck 64 | - whitespace 65 | # - cyclop 66 | # - errorlint 67 | # - exhaustive 68 | # - exhaustivestruct 69 | # - exportloopref 70 | # - forbidigo 71 | # - forcetypeassert 72 | # - funlen 73 | # - gci 74 | # - gochecknoglobals 75 | # - gochecknoinits 76 | # - gocognit 77 | # - godot 78 | # - goerr113 79 | # - gomnd 80 | # - ifshort 81 | # - lll 82 | # - nestif 83 | # - nilerr 84 | # - nlreturn 85 | # - noctx 86 | # - paralleltest 87 | # - scopelint 88 | # - tagliatelle 89 | # - testpackage 90 | # - thelper 91 | # - tparallel 92 | # - wastedassign 93 | # - wrapcheck 94 | # - wsl 95 | linters-settings: 96 | godox: 97 | keywords: 98 | - BUG 99 | - FIXME 100 | - HACK 101 | errcheck: 102 | check-type-assertions: true 103 | check-blank: true 104 | gocritic: 105 | enabled-checks: 106 | # Diagnostic 107 | - appendAssign 108 | - argOrder 109 | - badCond 110 | - caseOrder 111 | - codegenComment 112 | - commentedOutCode 113 | - deprecatedComment 114 | - dupArg 115 | - dupBranchBody 116 | - dupCase 117 | - dupSubExpr 118 | - exitAfterDefer 119 | - flagDeref 120 | - flagName 121 | - nilValReturn 122 | - offBy1 123 | - sloppyReassign 124 | - weakCond 125 | - octalLiteral 126 | 127 | # Performance 128 | - appendCombine 129 | - equalFold 130 | - hugeParam 131 | - indexAlloc 132 | - rangeExprCopy 133 | - rangeValCopy 134 | 135 | # Style 136 | - assignOp 137 | - boolExprSimplify 138 | - captLocal 139 | - commentFormatting 140 | - commentedOutImport 141 | - defaultCaseOrder 142 | - docStub 143 | - elseif 144 | - emptyFallthrough 145 | - emptyStringTest 146 | - hexLiteral 147 | - methodExprCall 148 | - regexpMust 149 | - singleCaseSwitch 150 | - sloppyLen 151 | - stringXbytes 152 | - switchTrue 153 | - typeAssertChain 154 | - typeSwitchVar 155 | - underef 156 | - unlabelStmt 157 | - unlambda 158 | - unslice 159 | - valSwap 160 | - wrapperFunc 161 | - yodaStyleExpr 162 | # - ifElseChain 163 | 164 | # Opinionated 165 | - builtinShadow 166 | - importShadow 167 | - initClause 168 | - nestingReduce 169 | - paramTypeCombine 170 | - ptrToRefParam 171 | - typeUnparen 172 | - unnamedResult 173 | - unnecessaryBlock 174 | nolintlint: 175 | # Enable to ensure that nolint directives are all used. Default is true. 176 | allow-unused: false 177 | # Disable to ensure that nolint directives don't have a leading space. Default is true. 178 | # TODO(lint): Enforce machine-readable `nolint` directives 179 | allow-leading-space: true 180 | # Exclude following linters from requiring an explanation. Default is []. 181 | allow-no-explanation: [] 182 | # Enable to require an explanation of nonzero length after each nolint directive. Default is false. 183 | # TODO(lint): Enforce explanations for `nolint` directives 184 | require-explanation: false 185 | # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. 186 | require-specific: true 187 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL:=/usr/bin/env bash 2 | .PHONY: build release publish 3 | build: 4 | mkdir tmp || : 5 | rm -f tmp/builder_linux_amd64 tmp/builder_darwin_amd64 6 | env CGO_ENABLED=0 go build -o tmp/mmbuilder_linux_amd64 cmd/mmbuild/main.go 7 | env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o tmp/mmbuilder_darwin_amd64 cmd/mmbuild/main.go 8 | 9 | publish: 10 | if [ -z "${TAG}" ]; then echo "Tag is not set"; exit 1; fi 11 | #go get k8s.io/release/cmd/publish-release 12 | #go run cmd/publish-release/main.go github \ 13 | publish-release github --nomock \ 14 | --repo=mattermost/builder --tag=${TAG} \ 15 | --asset="tmp/mmbuilder_linux_amd64:Mattermost Builder for linux/amd64" \ 16 | --asset="tmp/mmbuilder_darwin_amd64:Mattermost Builder for darwin/amd64" 17 | 18 | release: build publish 19 | 20 | ##@ Helpers 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `mmbuild`: The Mattermost Build System 2 | 3 | The `mmbuild` CLI is a general purpose (ie not Mattermost-specific) 4 | that inserts a layer between a builder (for example `make`) and the 5 | CI/CD system that actually runs it (for example GitLab which powers the mattermost builds) to achieve modern Supply Chain Security features 6 | even when the underlying CI/CD engine does not support them. 7 | 8 | This repository contains the CLI for the Mattermost build system. This is a thin 9 | repo, which leverages the code currently hosted in 10 | [mattermost/cicd-sdk](https://github.com/mattermost/cicd-sdk) to do its job. 11 | 12 | ## Purpose 13 | 14 | The main goal of `mmbuild` is to enable any CI/CD system to secure its build 15 | with the latest Supply Chain Security technologies like provenance attestations, 16 | digital signatures and SBOMs. 17 | 18 | `mmbuild` controls the inputs and outputs of a build. It allows a project 19 | to have predicable (ie reproducible) outcomes by feeding specific artifacts 20 | and by controlling the environment where the builder runs. 21 | 22 | Builds can be chained together in a pipeline by passing common environment 23 | variables between them and by feeding the artifacts from a build as the 24 | build materials from the next without relying on the artifacts of the 25 | CI/CD engine running the job. 26 | 27 | Any build can be replayed by consuming the provenance attestation from 28 | produced after every successful run. 29 | 30 | ## Features 31 | 32 | The following are some of the features of the `mmbuild` system. It is not comprehensive and hopefully its up to date: 33 | 34 | * Builds are defined from a YAML configuration file that lives in the project 35 | repository. 36 | 37 | * Provenance attestations: Runs generate (and consume as inputs) 38 | [in-toto](https://in-toto.io) attestations with [SLSA](https://slsa.dev) 39 | v0.2 predicates. 40 | 41 | * Support for loading environment variables from different sources: 1:1 from 42 | the running environment, hardcoded in the config file or from a secrets backend. 43 | 44 | * Extendable handlers that can be used to add more builders to `mmbuild`. The 45 | initial version of mmbuild has a handler for running `make`. 46 | 47 | * Pluggable [storage backend system](docs/storage.md) supporting build materials 48 | stored in a variety of backend. Currently s3, http, local filesystems and git are 49 | supported. More builders can be added if fetching artifacts from other systems 50 | is needed. 51 | 52 | * Native git repository cloning, avoids having a separate clone step in the 53 | pipeline. 54 | 55 | * Smarter text replacements. Before running a build, `mmbuild` can search 56 | and replace in files flags to specified values which can be read from secrets. 57 | 58 | ### Upcoming Features in the Roadmap 59 | 60 | The following features have not yet implemented but are planned for 61 | future releases: 62 | 63 | * Software Build of Materials (SBoM): Builds can generate SPDX SBOMs describing 64 | the artifacts the produce. 65 | 66 | 67 | * Digital Signatures: The most important part missing for now is 68 | supporting digital signatures for artifacts and container images but 69 | also for the attestations and SBOMs. Before accepting artifacts in 70 | a build, their provenance should be cryptographically checked. 71 | 72 | ## Design 73 | 74 | The Mattermost build system takes some ideas from the 75 | [Secure Software Factory](https://docs.google.com/document/d/1FwyOIDramwCnivuvUxrMmHmCr02ARoA3jw76o1mGfGQ), 76 | a secure supply chain reference implementation from the [OpenSSF](https://openssf.org/). 77 | 78 | The build replay system uses [in-toto](https://in-toto.io/) attestations with 79 | [SLSA](https://slsa.dev/) [v0.2 predicates](https://slsa.dev/provenance/v0.2) that allow 80 | `mmbuilder` to execute a builder with the captured metadata of a previous run. -------------------------------------------------------------------------------- /cmd/mmbuild/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/mattermost/cicd-sdk/pkg/build" 7 | "github.com/pkg/errors" 8 | "github.com/sirupsen/logrus" 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | var rootCmd = &cobra.Command{} 13 | 14 | var buildCmd = &cobra.Command{ 15 | Use: "build", 16 | // SilenceUsage: true, 17 | SilenceErrors: true, 18 | RunE: func(cmd *cobra.Command, args []string) error { 19 | return runBuild(bOpts) 20 | }, 21 | } 22 | 23 | var replayCmd = &cobra.Command{ 24 | Use: "replay", 25 | SilenceErrors: true, 26 | Args: cobra.ExactArgs(1), 27 | RunE: func(cmd *cobra.Command, args []string) error { 28 | return replayBuild(args[0], rOpts) 29 | }, 30 | } 31 | 32 | type buildOpts = struct { 33 | forceBuild bool 34 | SBOM bool 35 | configFile string 36 | workDir string 37 | } 38 | 39 | type replayOpts = struct { 40 | workDir string 41 | } 42 | 43 | var ( 44 | bOpts = &buildOpts{} 45 | rOpts = &replayOpts{} 46 | ) 47 | 48 | func init() { 49 | // Options for mmbuild build 50 | buildCmd.PersistentFlags().StringVar( 51 | &bOpts.configFile, "conf", "", "configuration file for the build", 52 | ) 53 | buildCmd.PersistentFlags().StringVarP( 54 | &bOpts.workDir, "workdir", "w", ".", "working directory where the build will run", 55 | ) 56 | buildCmd.PersistentFlags().BoolVarP( 57 | &bOpts.forceBuild, "force", "f", false, "execute the builder even if artifacts are found", 58 | ) 59 | buildCmd.PersistentFlags().BoolVar( 60 | &bOpts.SBOM, "sbom", false, "write an sbom to the workind directory after building", 61 | ) 62 | 63 | // Options for mmbuild replay 64 | replayCmd.PersistentFlags().StringVarP( 65 | &rOpts.workDir, "workdir", "w", ".", "working directory where the replay will run", 66 | ) 67 | replayCmd.PersistentFlags().BoolVarP( 68 | &bOpts.forceBuild, "force", "f", false, "execute the builder even if artifacts are found", 69 | ) 70 | 71 | rootCmd.AddCommand(buildCmd) 72 | rootCmd.AddCommand(replayCmd) 73 | } 74 | 75 | func runBuild(opts *buildOpts) (err error) { 76 | var b *build.Build 77 | if opts.configFile == "" { 78 | b, err = build.NewFromConfigFile(filepath.Join(opts.workDir, build.ConfigFileName)) 79 | } else { 80 | b, err = build.NewFromConfigFile(opts.configFile) 81 | } 82 | if err != nil { 83 | return errors.Wrap(err, "creating new build") 84 | } 85 | 86 | b.Options().SBOM = opts.SBOM 87 | b.Options().Workdir = opts.workDir 88 | b.Options().ForceBuild = opts.forceBuild 89 | 90 | run := b.Run() 91 | return errors.Wrap(run.Execute(), "executing build run") 92 | } 93 | 94 | func replayBuild(attestationPath string, ropts *replayOpts) (err error) { 95 | opts := &build.Options{Workdir: ropts.workDir} 96 | b, err := build.NewFromAttestation(attestationPath, opts) 97 | if err != nil { 98 | return errors.Wrap(err, "creating build") 99 | } 100 | 101 | return errors.Wrap(b.RunAttestation(attestationPath), "executing replay run") 102 | } 103 | 104 | func main() { 105 | if err := rootCmd.Execute(); err != nil { 106 | logrus.Fatal(err) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /docs/builds.HOWTO.md: -------------------------------------------------------------------------------- 1 | # Building Projects With mmbuild 2 | 3 | This guide explains how to run a build using `mmbuild`. 4 | 5 | 6 | - [Basic flow](#basic-flow) 7 | - [Configuration File](#configuration-file) 8 | - [runner](#runner) 9 | - [artifacts](#artifacts) 10 | - [Provenance Metadata](#provenance-metadata) 11 | - [Environment](#environment) 12 | - [Materials](#materials) 13 | - [Main Source Repository](#main-source-repository) 14 | - [Running the Build](#running-the-build) 15 | - [Command Line Interface](#command-line-interface) 16 | - [Invoking mmbuild:](#invoking-mmbuild) 17 | - [Exit Codes](#exit-codes) 18 | - [Output and logs](#output-and-logs) 19 | - [Running mmbuild in GitLab](#running-mmbuild-in-gitlab) 20 | - [Sharing the Environment](#sharing-the-environment) 21 | - [Staging Path](#staging-path) 22 | - [Concepts](#concepts) 23 | 24 | 25 | ## Basic flow 26 | 27 | A build managed by `mmbuild` in its most basic form will go through the following flow: 28 | 29 | 1. Read a build configuration file 30 | 2. Pull all build materials 31 | 3. Set up a controlled environment as defined in the build configuration 32 | 4. Invoke the selected runner 33 | 5. Ensure all artifacts are produced 34 | 6. Store the build outputs and its provenance attestation 35 | 36 | ## Configuration File 37 | 38 | The `mmbuild` configuration file will usually live inside the main source 39 | repository of the project. When the builder runs, the first thing it will do is try 40 | to look for the file in the specified directory. 41 | 42 | Here is an example, basic configuration file: 43 | 44 | ```yaml 45 | --- 46 | runner: 47 | id: make 48 | params: ["compile"] 49 | provenance: /tmp/slsa/ 50 | artifacts: 51 | destination: s3://mattermost-development-test/build-test/ 52 | files: ["binary"] 53 | env: 54 | - var: SHA_COMMIT 55 | - var: SHA_COMMIT_WITH_VAL 56 | value: b739074e0260def700eb13b2aa6091cae9366327 57 | materials: 58 | - uri: s3://mattermost-development-test/materials/add-on.tar.gz 59 | ``` 60 | 61 | Let's go step by step thhrough what this configuration does: 62 | 63 | ### runner 64 | 65 | `mmbuild` supports pluggable runners. For now only one is implemented: `make`. 66 | This is a simple runner that calls make passing it the defined parameters. In the 67 | example above, there is one parameter, "compile". This is equivalent to 68 | running this in your shell: 69 | 70 | ```bash 71 | make compile 72 | ``` 73 | 74 | The difference here from running it manually is that the environment is controlled 75 | by mmbuild and all materials are made available beforehand to the runner. 76 | 77 | ### artifacts 78 | 79 | When the example above runs, it expects the runner to produce one artifact: a file 80 | called simply `binary`. The path of the artifact is relative to the working directory 81 | passed with the `-w` flag to `mmbuild`. 82 | 83 | The other key in the artifacts section of the file is `destination:`. This value points 84 | to a storage location where all artifacts will be stored after the build runs. For more 85 | info about the backends see the [storage document](storage.md). All artifacts will be 86 | stored inside of a subdirectory in the destination URI formed by appending the 87 | `$MMBUILD_STAGING_PATH` value (see [Staging Path](#staging-path) below). 88 | 89 | #### Provenance Metadata 90 | 91 | The artifacts section also determines where the provenance metadata will be written. 92 | `mmbuild` will always write the provenance attestation in the artifacts destination, under 93 | the `MMBUILD_STAGING_PATH`. The Mattermost build system makes available the full URL 94 | in the `MMBUILD_STAGING_URL` variable, which means that you can retrieve the 95 | provenance attestation from this location: 96 | 97 | ``` 98 | ${MMBUILD_STAGING_URL}/provenance.json 99 | ``` 100 | 101 | ### Environment 102 | 103 | In this example, the builder will feed two environment variables to the runner. The way 104 | these two are defined has a slight difference: 105 | 106 | ```yaml 107 | env: 108 | - var: SHA_COMMIT 109 | - var: SHA_COMMIT_WITH_VAL 110 | value: b739074e0260def700eb13b2aa6091cae9366327 111 | ``` 112 | 113 | The first variable `SHA_COMMIT` will be read from `mmbuild`'s running environment and 114 | passed through to the runner. The second variable will be defined to the runner with 115 | the fixed value from the config file `b73907...`. 116 | 117 | ### Materials 118 | 119 | The last part of the file lists the building materials. In the exaple, the builder will 120 | download a single file and make it available for the runner inside the materials directory. 121 | This directory can be used byt the runner and its scripts by reading the `MMBUILD_MATERIALS_DIR` 122 | environment variable. 123 | 124 | In this example, the build material entry: 125 | 126 | ``` 127 | s3://mattermost-development-test/materials/add-on.tar.gz 128 | ``` 129 | 130 | Will be made available to the make runner in: 131 | 132 | ``` 133 | ${MMBUILD_MATERIALS_DIR}/add-on.tar.gz 134 | ``` 135 | 136 | Note that the current mmbuild version will only handle single files as materials, recursive 137 | directory copying is a feature to be implemented in the future. 138 | 139 | #### Main Source Repository 140 | 141 | It is not required to list the main source repository in the build materials section. 142 | 143 | When running a build, `mmbuild` will detect if the working directory is a git repository 144 | and record it as the first build material in the provenance attestation. This behavior 145 | is currently hardcoded. 146 | 147 | ## Running the Build 148 | 149 | ### Command Line Interface 150 | 151 | The build subcommand in Version 0.2 of `mmbuild` has a simple CLI interface with 152 | just a few flags for now: 153 | 154 | ``` 155 | ]$ mmbuild build --help 156 | 157 | Usage: 158 | build [flags] 159 | 160 | Flags: 161 | --conf string configuration file for the build 162 | -h, --help help for build 163 | -w, --workdir string working directory where the build will run (default ".") 164 | 165 | ``` 166 | 167 | `-w` or `--workdir` points to the working directory where the main source code lives. 168 | By default, mmbuild will look in this directory for a file called `matterbuild.yaml` at 169 | the root of the repo and use it as its configuration file. It defaults to the current 170 | working directory. 171 | 172 | The `--conf` flag allows to specify a different configuration file. 173 | 174 | ### Invoking mmbuild: 175 | 176 | To start a build, simply execute the `mmbuild` binary and point it to the root of the 177 | repository: 178 | 179 | ``` 180 | ]$ mmbuild build -w Projects/repository/ 181 | INFO[0000] Loading build configuration from Projects/repository/matterbuild.yaml 182 | INFO[0000] Replacing 1 configuration variables in YAML code ([PLUGIN_STORE_URL]) 183 | INFO[0000] > YAML conf variable SHA_COMMIT_WITH_VAL set to value 184 | 'b739074e0260def700eb13b2aa6091cae9366327' from predefined environment 185 | INFO[0000] No configuration variables found in YAML code 186 | INFO[0000] Build conf: 187 | .... (rest of output trimmed) 188 | ``` 189 | 190 | ### Exit Codes 191 | 192 | mmbuild supports only exit code 0 for success and non-zero for failures. 193 | 194 | ### Output and logs 195 | 196 | All output is written to STDERR. In addition, the output of the runner is captured to a 197 | logfile. Which is currently written to the system temporary directory (this should change 198 | in future versions). 199 | 200 | ## Running mmbuild in GitLab 201 | 202 | `mmbuild` is designed to sit between CICD system (ie GitLab) and the underlying runner 203 | (ie `make`). This way it can be started by the CI and control the I/O of the runner. 204 | 205 | As of this writing, the current approach to run `mmbuild` in a pipeline involves downloading 206 | the binary from the latest GitHub release and executing it in the host container[^1]. As 207 | releases are more solid this approach will change and binary verification should be performed. 208 | The following `.gitlab-ci.yml` file has an example of building the mattermost webapp repo: 209 | 210 | [^1]: Current plans are to make mmbuild available in a container image. 211 | 212 | ```yaml 213 | workflow: 214 | rules: 215 | - if: '$CI_PIPELINE_SOURCE != "push"' 216 | 217 | stages: 218 | - build 219 | 220 | clone: 221 | stage: build 222 | image: $HOST_IMAGE 223 | script: 224 | - git clone https://github.com/mattermost/mattermost-webapp.git --depth=1 225 | artifacts: 226 | paths: 227 | - mattermost-webapp 228 | mmbuild: 229 | stage: build 230 | image: $HOST_IMAGE 231 | needs: 232 | - clone 233 | script: 234 | - cd mattermost-webapp 235 | - curl -Lo mmbuild https://github.com/mattermost/builder/releases/download/$MMBUILDER_VERSION/mmbuilder_linux_amd64 236 | - chmod 0755 mmbuild 237 | - ./mmbuilder build 238 | artifacts: 239 | reports: 240 | dotenv: mattermost-webapp/build.env 241 | variables: 242 | HOST_IMAGE: $CI_REGISTRY/mattermost/ci/images/mattermost-build-webapp:20210524_node-16 243 | MMBUILDER_VERSION: v0.0.2 244 | ``` 245 | 246 | ### Sharing the Environment 247 | 248 | At some point, a more complicated pipeline will have to chaing several builds together. In order to pass 249 | values among them, `mmbuild` sets a few environment variables after each run. In the example above, note 250 | under the `artifacts:` section how the configuration is exporting `mmbuild`'s environment by reading 251 | the `build.env` dotenv report. This gives the next job in the pipeline a way to consume values from 252 | the `mmbuild` execution. 253 | 254 | Currently, the two variables that are exported are: 255 | 256 | * `MMBUILD_STAGING_PATH`: The computed hash to content-address the build 257 | * `MMBUILD_STAGING_URL`: The full URI pointing to where the artifacts are staged 258 | 259 | ## Staging Path 260 | 261 | Each build run can be content-addressed by its `STAGING_PATH`. The staging path of a build 262 | is a sha256 hash constructed by computing the build's materials source and variables[^2]. 263 | 264 | [^2]: As of this writing, the STAGING_PATH computation is not taking into account the 265 | environment, see [issue #19 in mattermost/cicd-sdk](https://github.com/mattermost/cicd-sdk/issues/19) 266 | for more info. 267 | 268 | The idea behind the value is to have a way to address a build by its inputs. If you 269 | want to check if artifacts exist for a specific build, just check the artifacts directory 270 | under the `STAGING_PATH` and you know. 271 | 272 | ## Concepts 273 | Some of the docs and concepts in mmbuild use the [SLSA](https://slsa.dev/) 274 | vocabulary. Some terms have simple 1:1 equivalents to common DevOps 275 | terminology and some are new but are important to understand: 276 | 277 | * **Provenance:** A piece of metadata that provides information about the origin 278 | of a build's artifacts. The provenance metadata describes what _ingredients_ 279 | went into a build, what process was applied to transform the inputs and 280 | finally what came out of the build. 281 | 282 | * **Attestation:** A file making a statement or verification about certain subjects. 283 | It will be often found as "provenance attestation", referring a file that _attests_ to 284 | the origin of a bunch of artifacts. 285 | 286 | * **Subjects:** Subjects are the artifacts described by an attestation. They can be 287 | the artifacts of a build, but not necesarily. Also, listing artifacts in a 288 | provenance attestation does not imply a complete listing of every file a build produced. 289 | 290 | * **Materials:** A build inputs. When a build runs, it will frequently pull packages 291 | it needs to assmble the project. These external files are called materials. Everything 292 | that goes into a project to assemble the final product is a material. 293 | 294 | * **Staging Path:** A sha256 hash computed from a builds inputs, source and environment. 295 | It allows consumers of the build to content-address the run and its artifacts. 296 | 297 | * **Runner:** mmbuild works by controlling a _runner_'s environment and inputs. A runner 298 | is a program executed by the build system that does the actual work of building the 299 | project. Most promiment example: `make`. 300 | -------------------------------------------------------------------------------- /docs/provenance.md: -------------------------------------------------------------------------------- 1 | # Provenance Metdata 2 | 3 | 4 | - [Why Do We Need Provenance Metadata?](#why-do-we-need-provenance-metadata) 5 | - [Metadata Structure](#metadata-structure) 6 | - [Main Sections](#main-sections) 7 | - [Subjects](#subjects) 8 | - [Materials](#materials) 9 | - [Invocation](#invocation) 10 | - [Build Configuration File](#build-configuration-file) 11 | 12 | 13 | ## Why Do We Need Provenance Metadata? 14 | 15 | Runs executed by `mmbuild` produce provanance attestations that capture the 16 | information that the system used to produce a given set of artifacts. 17 | Theoretically, a controlled build can be rerun using the same inputs and 18 | under the same environment and produce the same artifacts, verifiable bit 19 | by bit. 20 | 21 | When running the `mmbuild replay` subcommand, the Mattermost build system 22 | can read the provenance metdata and execute the build again as it was run 23 | when it was originally executed. 24 | 25 | ## Metadata Structure 26 | 27 | The metadata files produced by mmbuild conform to the in-toto attestation 28 | specification. The [in-toto](https://in-toto.io/) framework provides software 29 | build systems a specification to describe and verify each stage of the build 30 | as it runs. 31 | 32 | An attestation describes _subkects_ and a _predicate_. The predicate in the 33 | `mmbuild` runs conforms to the [SLSA framework](https://slsa.dev/) 34 | (Supply chain Levels for Software Artifacts) 35 | [version 0.2 provenance attestation](https://slsa.dev/provenance/v0.2). 36 | 37 | Here is an example of a build metadata file: 38 | 39 | ```json 40 | { 41 | "_type": "https://in-toto.io/Statement/v0.1", 42 | "predicateType": "https://slsa.dev/provenance/v0.2", 43 | "subject": [ 44 | { 45 | "name": "mattermost-webapp.tar.gz", 46 | "digest": { 47 | "sha256": "f0506779127b08be23e37c6022d1fd51418bb0b6481665fdeb51bd4bbed904d4", 48 | "sha512": "f56b6f3d60a59fce7675d5f7f564a34b5c9632401d2d00ac7a67bf6258458a51420283e1d99e18113668545c55e6ac95e5d5b1b19e5acaa886f9842c5f10080e" 49 | } 50 | } 51 | ], 52 | "predicate": { 53 | "builder": { 54 | "id": "MatterBuild/v0.1" 55 | }, 56 | "buildType": "make", 57 | "invocation": { 58 | "configSource": { 59 | "uri": "matterbuild.yaml", 60 | "digest": { 61 | "sha1": "53868e12c770d6da4195955cf94a5b53b82a7c86" 62 | } 63 | }, 64 | "parameters": [ 65 | "package" 66 | ], 67 | "environment": { 68 | "PLUGIN_STORE_URL": "https://plugins-store.test.mattermost.com/release", 69 | } 70 | }, 71 | "metadata": { 72 | "buildStartedOn": "2021-12-21T01:19:10.727607258Z", 73 | "buildFinishedOn": "2021-12-21T01:19:13.248116432Z", 74 | "completeness": { 75 | "parameters": true, 76 | "environment": true, 77 | "materials": true 78 | }, 79 | "reproducible": true 80 | }, 81 | "materials": [ 82 | { 83 | "uri": "git+https://github.com/mattermost/mattermost-webapp.git", 84 | "digest": { 85 | "sha1": "53868e12c770d6da4195955cf94a5b53b82a7c86" 86 | } 87 | } 88 | ] 89 | } 90 | } 91 | 92 | ``` 93 | ## Main Sections 94 | 95 | Let's go over some of the important parts of the example above. 96 | 97 | ### Subjects 98 | 99 | The subjects in an attestation are the artifacts produced after a build. 100 | In the example above, `mmbuild` ran and produced one file: 101 | `mattermost-webapp.tar.gz`. One provenance file can attest to the origin 102 | of any number of subjects (artifacts). The files are recorded along with 103 | their sha256 and sha512 hashes. 104 | 105 | ### Materials 106 | 107 | The build materials are all files consumed by the build to assemble its 108 | artifacts. In the example above, only one build material is defined: 109 | the project's source code, which was cloned from the `mattermost/mattermost-webapp` 110 | repository. The build ran at commit 53868e12c770d6da4195955cf94a5b53b82a7c86. 111 | 112 | ### Invocation 113 | 114 | The invocation is the actual command that `mmbuild` ran to execute the 115 | builder. In this case the buildType is _make_. This part in the spec is arbitrary, 116 | the value is written by the `mmbuild` `make` builder and the sole parameter is 117 | `package`. If replayed, the build system would use the make builder to run 118 | `make module` in the repo. 119 | 120 | The environment variables defined when the build ran are captured in the `environment` 121 | key. There is one sole variable in the example: `PLUGIN_STORE_URL`. 122 | 123 | ### Build Configuration File 124 | 125 | The provenance attestation registers the configuration file used to run the build. 126 | In our case, this points to the `matterbuild.yaml` used by `mmbuild` to run. In the 127 | example, the URI is just the filename (matterbuild.yaml) which means that the file 128 | was read from the source repository at the commit shown[^1] 129 | 130 | [^1]: The syntax to specify artifacts in git repos is abigous in the spec. As SLSA 131 | is rapidly evolving, this will surely change in the upcoming versions. 132 | 133 | -------------------------------------------------------------------------------- /docs/storage.md: -------------------------------------------------------------------------------- 1 | # Storage Backends 2 | 3 | `mmbuild` can read and write objects (files) to different storage 4 | backends which can be used as build materials (inputs) or build 5 | subjects (artifacts). 6 | 7 | ## Storage URLs 8 | 9 | Objects are referenced to a location in the backend system using 10 | [SPDX Locator](https://spdx.github.io/spdx-spec/package-information/#77-package-download-location-field) URLs. These locators are compatible 11 | with standard URLs: 12 | 13 | ``` 14 | https://example.com/file.txt 15 | ``` 16 | 17 | But can also reference an object in time, stored in a VCS system with 18 | a specific transport: 19 | 20 | ``` 21 | git+https://git.myproject.org/MyProject#file.go 22 | 23 | git+ssh://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#file.go 24 | 25 | ``` 26 | 27 | Not all backend systems suport all I/O operations. Some of them are not 28 | yet implemented, and some of them don't make much sense. For example, storing 29 | objects in HTTP servers. 30 | 31 | ## Supported Backends: 32 | 33 | As of this writing, the supported backends include the following: 34 | 35 | | URI Prefix | Backend | 36 | | --- | --- | 37 | | file:// | Local filesystem | 38 | | s3:// | AWS S3 | 39 | | git://
git+https://
git+ssh:// | git repository | 40 | | http://
https:// | HTTP server | 41 | 42 | Backends are configured via environment variables. For example, the AWS S3 backend 43 | gets its credentials from env vars which are read by the s3 client. 44 | 45 | ## Extending the Storage System 46 | 47 | To add a new backend, add a new golang file with a struct implementing 48 | the [`object.Backend` interface](https://github.com/mattermost/cicd-sdk/blob/c9a662396e1ec40dea34ea4fb7c5770c133746ec/pkg/object/backends/backends.go#L10-L16). 49 | At the time of this writing the interface 50 | exposes these methods: 51 | 52 | ```golang 53 | type Backend interface { 54 | URLPrefix() string 55 | CopyObject(srcURL, destURL string) error 56 | Prefixes() []string 57 | PathExists(string) (bool, error) 58 | GetObjectHash(string) (map[string]string, error) 59 | } 60 | ``` 61 | 62 | The functions should be self explainatory from their names. 63 | 64 | Once the interface implementation is complete, simply add the new backend 65 | to the [list of supported backends](https://github.com/mattermost/cicd-sdk/blob/c9a662396e1ec40dea34ea4fb7c5770c133746ec/pkg/object/object.go#L29-L34) 66 | in the `object` package: 67 | 68 | ```golang 69 | // Add the implemented backends 70 | om.Backends = append(om.Backends, 71 | backends.NewFilesystemWithOptions(&backends.Options{}), 72 | backends.NewS3WithOptions(&backends.Options{}), 73 | backends.NewGitWithOptions(&backends.Options{}), 74 | backends.NewHTTPWithOptions(&backends.Options{}), 75 | ) 76 | ``` -------------------------------------------------------------------------------- /examples/server/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build package run stop run-client run-server run-haserver stop-haserver stop-client stop-server restart restart-server restart-client restart-haserver start-docker clean-dist clean nuke check-style check-client-style check-server-style check-unit-tests test dist prepare-enteprise run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows package-prep package-linux package-osx package-windows internal-test-web-client vet run-server-for-web-client-tests diff-config prepackaged-plugins prepackaged-binaries test-server test-server-ee test-server-quick test-server-race start-docker-check migrations-bindata new-migration migration-prereqs 2 | 3 | ROOT := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 4 | 5 | ifeq ($(OS),Windows_NT) 6 | PLATFORM := Windows 7 | else 8 | PLATFORM := $(shell uname) 9 | endif 10 | 11 | # Set an environment variable on Linux used to resolve `docker.host.internal` inconsistencies with 12 | # docker. This can be reworked once https://github.com/docker/for-linux/issues/264 is resolved 13 | # satisfactorily. 14 | ifeq ($(PLATFORM),Linux) 15 | export IS_LINUX = -linux 16 | else 17 | export IS_LINUX = 18 | endif 19 | 20 | IS_CI ?= false 21 | # Build Flags 22 | BUILD_NUMBER ?= $(BUILD_NUMBER:) 23 | BUILD_DATE = $(shell date -u) 24 | BUILD_HASH = $(shell git rev-parse HEAD) 25 | # If we don't set the build number it defaults to dev 26 | ifeq ($(BUILD_NUMBER),) 27 | BUILD_DATE := n/a 28 | BUILD_NUMBER := dev 29 | endif 30 | BUILD_ENTERPRISE_DIR ?= ../enterprise 31 | BUILD_ENTERPRISE ?= true 32 | BUILD_ENTERPRISE_READY = false 33 | BUILD_TYPE_NAME = team 34 | BUILD_HASH_ENTERPRISE = none 35 | ifneq ($(wildcard $(BUILD_ENTERPRISE_DIR)/.),) 36 | ifeq ($(BUILD_ENTERPRISE),true) 37 | BUILD_ENTERPRISE_READY = true 38 | BUILD_TYPE_NAME = enterprise 39 | BUILD_HASH_ENTERPRISE = $(shell cd $(BUILD_ENTERPRISE_DIR) && git rev-parse HEAD) 40 | else 41 | BUILD_ENTERPRISE_READY = false 42 | BUILD_TYPE_NAME = team 43 | endif 44 | else 45 | BUILD_ENTERPRISE_READY = false 46 | BUILD_TYPE_NAME = team 47 | endif 48 | BUILD_WEBAPP_DIR ?= $(MMBUILD_MATERIALS_DIR) 49 | BUILD_WEBAPP_DIR ?= ../mattermost-webapp 50 | BUILD_CLIENT = false 51 | BUILD_HASH_CLIENT = independant 52 | ifneq ($(wildcard $(BUILD_WEBAPP_DIR)/.),) 53 | ifeq ($(BUILD_CLIENT),true) 54 | BUILD_CLIENT = true 55 | BUILD_HASH_CLIENT = $(shell cd $(BUILD_WEBAPP_DIR) && git rev-parse HEAD) 56 | else 57 | BUILD_CLIENT = false 58 | endif 59 | else 60 | BUILD_CLIENT = false 61 | endif 62 | 63 | # We need current user's UID for `run-haserver` so docker compose does not run server 64 | # as root and mess up file permissions for devs. When running like this HOME will be blank 65 | # and docker will add '/', so we need to set the go-build cache location or we'll get 66 | # permission errors on build as it tries to create a cache in filesystem root. 67 | export CURRENT_UID = $(shell id -u):$(shell id -g) 68 | ifeq ($(HOME),/) 69 | export XDG_CACHE_HOME = /tmp/go-cache/ 70 | endif 71 | 72 | # Go Flags 73 | GOFLAGS ?= $(GOFLAGS:) 74 | # We need to export GOBIN to allow it to be set 75 | # for processes spawned from the Makefile 76 | export GOBIN ?= $(PWD)/bin 77 | GO=go 78 | DELVE=dlv 79 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)" 80 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)" 81 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)" 82 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)" 83 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)" 84 | 85 | GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1) 86 | GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2) 87 | MINIMUM_SUPPORTED_GO_MAJOR_VERSION = 1 88 | MINIMUM_SUPPORTED_GO_MINOR_VERSION = 15 89 | GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION).$(MINIMUM_SUPPORTED_GO_MINOR_VERSION) 90 | 91 | # GOOS/GOARCH of the build host, used to determine whether we're cross-compiling or not 92 | BUILDER_GOOS_GOARCH="$(shell $(GO) env GOOS)_$(shell $(GO) env GOARCH)" 93 | 94 | PLATFORM_FILES="./cmd/mattermost" 95 | 96 | # Output paths 97 | DIST_ROOT=dist 98 | DIST_PATH=$(DIST_ROOT)/mattermost 99 | DIST_PATH_LIN_AMD64=$(DIST_ROOT)/linux_amd64/mattermost 100 | DIST_PATH_LIN_ARM64=$(DIST_ROOT)/linux_arm64/mattermost 101 | DIST_PATH_OSX_AMD64=$(DIST_ROOT)/osx_amd64/mattermost 102 | DIST_PATH_OSX_ARM64=$(DIST_ROOT)/osx_arm64/mattermost 103 | DIST_PATH_WIN=$(DIST_ROOT)/windows/mattermost 104 | 105 | # Tests 106 | TESTS=. 107 | 108 | # Packages lists 109 | TE_PACKAGES=$(shell $(GO) list ./... | grep -v ./data) 110 | 111 | TEMPLATES_DIR=templates 112 | 113 | # Plugins Packages. These are defined in the build configuration 114 | # file matterbuild.yaml 115 | ifndef PLUGIN_PACKAGES 116 | PLUGIN_PACKAGES=$(shell grep -A1 "var: MM_PLUGIN" matterbuild.yaml | grep value: | awk '{print $2}' | tr "\n", " ") 117 | endif 118 | 119 | # Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target 120 | ifeq ($(BUILD_ENTERPRISE_READY),true) 121 | IGNORE:=$(shell echo Enterprise build selected, preparing) 122 | IGNORE:=$(shell rm -f imports/imports.go) 123 | IGNORE:=$(shell cp $(BUILD_ENTERPRISE_DIR)/imports/imports.go imports/) 124 | IGNORE:=$(shell rm -f enterprise) 125 | IGNORE:=$(shell ln -s $(BUILD_ENTERPRISE_DIR) enterprise) 126 | else 127 | IGNORE:=$(shell rm -f imports/imports.go) 128 | endif 129 | 130 | EE_PACKAGES=$(shell $(GO) list ./enterprise/...) 131 | 132 | ifeq ($(BUILD_ENTERPRISE_READY),true) 133 | ALL_PACKAGES=$(TE_PACKAGES) $(EE_PACKAGES) 134 | else 135 | ALL_PACKAGES=$(TE_PACKAGES) 136 | endif 137 | 138 | all: run ## Alias for 'run'. 139 | 140 | -include config.override.mk 141 | include config.mk 142 | include build/*.mk 143 | 144 | LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.MockCWS=$(MM_ENABLE_CWS_MOCK)" 145 | 146 | RUN_IN_BACKGROUND ?= 147 | ifeq ($(RUN_SERVER_IN_BACKGROUND),true) 148 | RUN_IN_BACKGROUND := & 149 | endif 150 | 151 | start-docker-check: 152 | ifeq (,$(findstring minio,$(ENABLED_DOCKER_SERVICES))) 153 | TEMP_DOCKER_SERVICES:=$(TEMP_DOCKER_SERVICES) minio 154 | endif 155 | ifeq ($(BUILD_ENTERPRISE_READY),true) 156 | ifeq (,$(findstring openldap,$(ENABLED_DOCKER_SERVICES))) 157 | TEMP_DOCKER_SERVICES:=$(TEMP_DOCKER_SERVICES) openldap 158 | endif 159 | ifeq (,$(findstring elasticsearch,$(ENABLED_DOCKER_SERVICES))) 160 | TEMP_DOCKER_SERVICES:=$(TEMP_DOCKER_SERVICES) elasticsearch 161 | endif 162 | endif 163 | ENABLED_DOCKER_SERVICES:=$(ENABLED_DOCKER_SERVICES) $(TEMP_DOCKER_SERVICES) 164 | 165 | start-docker: ## Starts the docker containers for local development. 166 | ifneq ($(IS_CI),false) 167 | @echo CI Build: skipping docker start 168 | else ifeq ($(MM_NO_DOCKER),true) 169 | @echo No Docker Enabled: skipping docker start 170 | else 171 | @echo Starting docker containers 172 | 173 | $(GO) run ./build/docker-compose-generator/main.go $(ENABLED_DOCKER_SERVICES) | docker-compose -f docker-compose.makefile.yml -f /dev/stdin run --rm start_dependencies 174 | ifneq (,$(findstring openldap,$(ENABLED_DOCKER_SERVICES))) 175 | cat tests/${LDAP_DATA}-data.ldif | docker-compose -f docker-compose.makefile.yml exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest || true'; 176 | endif 177 | ifneq (,$(findstring mysql-read-replica,$(ENABLED_DOCKER_SERVICES))) 178 | ./scripts/replica-mysql-config.sh 179 | endif 180 | endif 181 | 182 | run-haserver: 183 | ifeq ($(BUILD_ENTERPRISE_READY),true) 184 | @echo Starting mattermost in an HA topology '(3 node cluster)' 185 | 186 | docker-compose -f docker-compose.yaml up --remove-orphans haproxy 187 | endif 188 | 189 | stop-haserver: 190 | @echo Stopping docker containers for HA topology 191 | docker-compose stop 192 | 193 | stop-docker: ## Stops the docker containers for local development. 194 | ifeq ($(MM_NO_DOCKER),true) 195 | @echo No Docker Enabled: skipping docker stop 196 | else 197 | @echo Stopping docker containers 198 | 199 | docker-compose stop 200 | endif 201 | 202 | clean-docker: ## Deletes the docker containers for local development. 203 | ifeq ($(MM_NO_DOCKER),true) 204 | @echo No Docker Enabled: skipping docker clean 205 | else 206 | @echo Removing docker containers 207 | 208 | docker-compose down -v 209 | docker-compose rm -v 210 | endif 211 | 212 | plugin-checker: 213 | $(GO) run $(GOFLAGS) ./plugin/checker 214 | 215 | #prepackaged-plugins: ## Populate the prepackaged-plugins directory 216 | # @echo Downloading prepackaged plugins 217 | # mkdir -p prepackaged_plugins 218 | # @cd prepackaged_plugins && for plugin_package in $(PLUGIN_PACKAGES) ; do \ 219 | # curl -f -O -L https://plugins-store.test.mattermost.com/release/$$plugin_package.tar.gz; \ 220 | # curl -f -O -L https://plugins-store.test.mattermost.com/release/$$plugin_package.tar.gz.sig; \ 221 | # done 222 | 223 | prepackaged-binaries: ## Populate the prepackaged-binaries to the bin directory 224 | ifeq ($(shell test -f bin/mmctl && printf "yes"),yes) 225 | @echo "MMCTL already exists in bin/mmctl not downloading a new version." 226 | else 227 | @scripts/download_mmctl_release.sh 228 | endif 229 | 230 | golangci-lint: ## Run golangci-lint on codebase 231 | # https://stackoverflow.com/a/677212/1027058 (check if a command exists or not) 232 | @if ! [ -x "$$(command -v golangci-lint)" ]; then \ 233 | echo "golangci-lint is not installed. Please see https://github.com/golangci/golangci-lint#install for installation instructions."; \ 234 | exit 1; \ 235 | fi; \ 236 | 237 | @echo Running golangci-lint 238 | golangci-lint run ./... 239 | ifeq ($(BUILD_ENTERPRISE_READY),true) 240 | ifneq ($(MM_NO_ENTERPRISE_LINT),true) 241 | golangci-lint run ./enterprise/... 242 | endif 243 | endif 244 | 245 | app-layers: ## Extract interface from App struct 246 | $(GO) get -modfile=go.tools.mod github.com/reflog/struct2interface 247 | $(GOBIN)/struct2interface -f "app" -o "app/app_iface.go" -p "app" -s "App" -i "AppIface" -t ./app/layer_generators/app_iface.go.tmpl 248 | $(GO) run ./app/layer_generators -in ./app/app_iface.go -out ./app/opentracing/opentracing_layer.go -template ./app/layer_generators/opentracing_layer.go.tmpl 249 | 250 | i18n-extract: ## Extract strings for translation from the source code 251 | $(GO) get -modfile=go.tools.mod github.com/mattermost/mattermost-utilities/mmgotool 252 | $(GOBIN)/mmgotool i18n extract --portal-dir="" 253 | 254 | i18n-check: ## Exit on empty translation strings and translation source strings 255 | $(GO) get -modfile=go.tools.mod github.com/mattermost/mattermost-utilities/mmgotool 256 | $(GOBIN)/mmgotool i18n clean-empty --portal-dir="" --check 257 | $(GOBIN)/mmgotool i18n check-empty-src --portal-dir="" 258 | 259 | store-mocks: ## Creates mock files. 260 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 261 | $(GOBIN)/mockery -dir store -all -output store/storetest/mocks -note 'Regenerate this file using `make store-mocks`.' 262 | 263 | telemetry-mocks: ## Creates mock files. 264 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 265 | $(GOBIN)/mockery -dir services/telemetry -all -output services/telemetry/mocks -note 'Regenerate this file using `make telemetry-mocks`.' 266 | 267 | store-layers: ## Generate layers for the store 268 | $(GO) generate $(GOFLAGS) ./store 269 | 270 | migration-prereqs: ## Builds prerequisite packages for migrations 271 | $(GO) get -modfile=go.tools.mod github.com/golang-migrate/migrate/v4/cmd/migrate 272 | 273 | new-migration: migration-prereqs ## Creates a new migration 274 | @echo "Generating new migration for mysql" 275 | $(GOBIN)/migrate create -ext sql -dir db/migrations/mysql -seq $(name) 276 | 277 | @echo "Generating new migration for postgres" 278 | $(GOBIN)/migrate create -ext sql -dir db/migrations/postgres -seq $(name) 279 | 280 | @echo "When you are done writing your migration, run 'make migrations'" 281 | 282 | migrations-bindata: ## Generates bindata migrations 283 | $(GO) get -modfile=go.tools.mod github.com/go-bindata/go-bindata/... 284 | 285 | @echo Generating bindata for migrations 286 | $(GO) generate $(GOFLAGS) ./db/migrations/ 287 | 288 | filestore-mocks: ## Creates mock files. 289 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 290 | $(GOBIN)/mockery -dir shared/filestore -all -output shared/filestore/mocks -note 'Regenerate this file using `make filestore-mocks`.' 291 | 292 | ldap-mocks: ## Creates mock files for ldap. 293 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 294 | $(GOBIN)/mockery -dir enterprise/ldap -all -output enterprise/ldap/mocks -note 'Regenerate this file using `make ldap-mocks`.' 295 | 296 | plugin-mocks: ## Creates mock files for plugins. 297 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 298 | $(GOBIN)/mockery -dir plugin -name API -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.' 299 | $(GOBIN)/mockery -dir plugin -name Hooks -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.' 300 | $(GOBIN)/mockery -dir plugin -name Driver -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.' 301 | 302 | einterfaces-mocks: ## Creates mock files for einterfaces. 303 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 304 | $(GOBIN)/mockery -dir einterfaces -all -output einterfaces/mocks -note 'Regenerate this file using `make einterfaces-mocks`.' 305 | 306 | searchengine-mocks: ## Creates mock files for searchengines. 307 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 308 | $(GOBIN)/mockery -dir services/searchengine -all -output services/searchengine/mocks -note 'Regenerate this file using `make searchengine-mocks`.' 309 | 310 | sharedchannel-mocks: ## Creates mock files for shared channels. 311 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 312 | $(GOBIN)/mockery -dir=./services/sharedchannel -name=ServerIface -output=./services/sharedchannel -inpkg -outpkg=sharedchannel -testonly -note 'Regenerate this file using `make sharedchannel-mocks`.' 313 | $(GOBIN)/mockery -dir=./services/sharedchannel -name=AppIface -output=./services/sharedchannel -inpkg -outpkg=sharedchannel -testonly -note 'Regenerate this file using `make sharedchannel-mocks`.' 314 | 315 | misc-mocks: ## Creates mocks for misc interfaces. 316 | $(GO) get -modfile=go.tools.mod github.com/vektra/mockery/... 317 | $(GOPATH)/bin/mockery -dir utils --name LicenseValidatorIface -output utils/mocks -note 'Regenerate this file using `make misc-mocks`.' 318 | 319 | pluginapi: ## Generates api and hooks glue code for plugins 320 | $(GO) generate $(GOFLAGS) ./plugin 321 | 322 | check-prereqs: ## Checks prerequisite software status. 323 | ./scripts/prereq-check.sh 324 | 325 | check-prereqs-enterprise: ## Checks prerequisite software status for enterprise. 326 | ifeq ($(BUILD_ENTERPRISE_READY),true) 327 | ./scripts/prereq-check-enterprise.sh 328 | endif 329 | 330 | check-style: golangci-lint plugin-checker vet ## Runs style/lint checks 331 | 332 | 333 | do-cover-file: ## Creates the test coverage report file. 334 | @echo "mode: count" > cover.out 335 | 336 | go-junit-report: 337 | $(GO) get -modfile=go.tools.mod github.com/jstemmer/go-junit-report 338 | 339 | test-compile: ## Compile tests. 340 | @echo COMPILE TESTS 341 | 342 | for package in $(TE_PACKAGES) $(EE_PACKAGES); do \ 343 | $(GO) test $(GOFLAGS) -c $$package; \ 344 | done 345 | 346 | test-db-migration: start-docker ## Gets diff of upgrade vs new instance schemas. 347 | ./scripts/mysql-migration-test.sh 6.0.0 348 | ./scripts/psql-migration-test.sh 6.0.0 349 | 350 | test-db-migration-v5: start-docker ## Gets diff of upgrade vs new instance schemas. 351 | ./scripts/mysql-migration-test.sh 5.0.0 352 | ./scripts/psql-migration-test.sh 5.0.0 353 | 354 | gomodtidy: 355 | @cp go.mod go.mod.orig 356 | @cp go.sum go.sum.orig 357 | $(GO) mod tidy 358 | @if [ "$$(diff go.mod go.mod.orig)" != "" -o "$$(diff go.sum go.sum.orig)" != "" ]; then \ 359 | echo "go.mod/go.sum was modified. \ndiff- $$(diff go.mod go.mod.orig) \n$$(diff go.sum go.sum.orig) \nRun \"go mod tidy\"."; \ 360 | rm go.*.orig; \ 361 | exit 1; \ 362 | fi; 363 | @rm go.*.orig; 364 | 365 | test-server-pre: check-prereqs-enterprise start-docker-check start-docker go-junit-report do-cover-file ## Runs tests. 366 | ifeq ($(BUILD_ENTERPRISE_READY),true) 367 | @echo Running all tests 368 | else 369 | @echo Running only TE tests 370 | endif 371 | 372 | test-server-race: test-server-pre 373 | ./scripts/test.sh "$(GO)" "-race $(GOFLAGS)" "$(ALL_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "90m" "atomic" 374 | ifneq ($(IS_CI),true) 375 | ifneq ($(MM_NO_DOCKER),true) 376 | ifneq ($(TEMP_DOCKER_SERVICES),) 377 | @echo Stopping temporary docker services 378 | docker-compose stop $(TEMP_DOCKER_SERVICES) 379 | endif 380 | endif 381 | endif 382 | 383 | test-server: test-server-pre 384 | ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(ALL_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "45m" "count" 385 | ifneq ($(IS_CI),true) 386 | ifneq ($(MM_NO_DOCKER),true) 387 | ifneq ($(TEMP_DOCKER_SERVICES),) 388 | @echo Stopping temporary docker services 389 | docker-compose stop $(TEMP_DOCKER_SERVICES) 390 | endif 391 | endif 392 | endif 393 | 394 | test-server-ee: check-prereqs-enterprise start-docker-check start-docker go-junit-report do-cover-file ## Runs EE tests. 395 | @echo Running only EE tests 396 | ./scripts/test.sh "$(GO)" "$(GOFLAGS)" "$(EE_PACKAGES)" "$(TESTS)" "$(TESTFLAGS)" "$(GOBIN)" "20m" "count" 397 | 398 | test-server-quick: check-prereqs-enterprise ## Runs only quick tests. 399 | ifeq ($(BUILD_ENTERPRISE_READY),true) 400 | @echo Running all tests 401 | $(GO) test $(GOFLAGS) -short $(ALL_PACKAGES) 402 | else 403 | @echo Running only TE tests 404 | $(GO) test $(GOFLAGS) -short $(TE_PACKAGES) 405 | endif 406 | 407 | internal-test-web-client: ## Runs web client tests. 408 | $(GO) run $(GOFLAGS) $(PLATFORM_FILES) test web_client_tests 409 | 410 | run-server-for-web-client-tests: ## Tests the server for web client. 411 | $(GO) run $(GOFLAGS) $(PLATFORM_FILES) test web_client_tests_server 412 | 413 | test-client: ## Test client app. 414 | @echo Running client tests 415 | 416 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) test 417 | 418 | test: test-server test-client ## Runs all checks and tests below (except race detection and postgres). 419 | 420 | cover: ## Runs the golang coverage tool. You must run the unit tests first. 421 | @echo Opening coverage info in browser. If this failed run make test first 422 | 423 | $(GO) tool cover -html=cover.out 424 | $(GO) tool cover -html=ecover.out 425 | 426 | test-data: run-server ## Add test data to the local instance. 427 | @if ! ./scripts/wait-for-system-start.sh; then \ 428 | make stop; \ 429 | fi 430 | 431 | @echo ServiceSettings.EnableLocalMode must be set to true. 432 | 433 | bin/mmctl config set TeamSettings.MaxUsersPerTeam 100 --local 434 | bin/mmctl sampledata -u 60 --local 435 | 436 | @echo You may need to restart the Mattermost server before using the following 437 | @echo ======================================================================== 438 | @echo Login with a system admin account username=sysadmin password=Sys@dmin-sample1 439 | @echo Login with a regular account username=user-1 password=SampleUs@r-1 440 | @echo ======================================================================== 441 | 442 | validate-go-version: ## Validates the installed version of go against Mattermost's minimum requirement. 443 | @if [ $(GO_MAJOR_VERSION) -gt $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION) ]; then \ 444 | exit 0 ;\ 445 | elif [ $(GO_MAJOR_VERSION) -lt $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION) ]; then \ 446 | echo '$(GO_VERSION_VALIDATION_ERR_MSG)';\ 447 | exit 1; \ 448 | elif [ $(GO_MINOR_VERSION) -lt $(MINIMUM_SUPPORTED_GO_MINOR_VERSION) ] ; then \ 449 | echo '$(GO_VERSION_VALIDATION_ERR_MSG)';\ 450 | exit 1; \ 451 | fi 452 | 453 | build-templates: ## Compile all mjml email templates 454 | cd $(TEMPLATES_DIR) && $(MAKE) build 455 | 456 | run-server: prepackaged-binaries validate-go-version start-docker ## Starts the server. 457 | @echo Running mattermost for development 458 | 459 | mkdir -p $(BUILD_WEBAPP_DIR)/dist/files 460 | $(GO) run $(GOFLAGS) -ldflags '$(LDFLAGS)' $(PLATFORM_FILES) $(RUN_IN_BACKGROUND) 461 | 462 | debug-server: start-docker ## Compile and start server using delve. 463 | mkdir -p $(BUILD_WEBAPP_DIR)/dist/files 464 | $(DELVE) debug $(PLATFORM_FILES) --build-flags="-ldflags '\ 465 | -X github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)\ 466 | -X \"github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)\"\ 467 | -X github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)\ 468 | -X github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\ 469 | -X github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'" 470 | 471 | debug-server-headless: start-docker ## Debug server from within an IDE like VSCode or IntelliJ. 472 | mkdir -p $(BUILD_WEBAPP_DIR)/dist/files 473 | $(DELVE) debug --headless --listen=:2345 --api-version=2 --accept-multiclient $(PLATFORM_FILES) --build-flags="-ldflags '\ 474 | -X github.com/mattermost/mattermost-server/v6/model.BuildNumber=$(BUILD_NUMBER)\ 475 | -X \"github.com/mattermost/mattermost-server/v6/model.BuildDate=$(BUILD_DATE)\"\ 476 | -X github.com/mattermost/mattermost-server/v6/model.BuildHash=$(BUILD_HASH)\ 477 | -X github.com/mattermost/mattermost-server/v6/model.BuildHashEnterprise=$(BUILD_HASH_ENTERPRISE)\ 478 | -X github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)'" 479 | 480 | run-cli: start-docker ## Runs CLI. 481 | @echo Running mattermost for development 482 | @echo Example should be like 'make ARGS="-version" run-cli' 483 | 484 | $(GO) run $(GOFLAGS) -ldflags '$(LDFLAGS)' $(PLATFORM_FILES) ${ARGS} 485 | 486 | run-client: ## Runs the webapp. 487 | @echo Running mattermost client for development 488 | 489 | ln -nfs $(BUILD_WEBAPP_DIR)/dist client 490 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) run 491 | 492 | run-client-fullmap: ## Legacy alias to run-client 493 | @echo Running mattermost client for development 494 | 495 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) run 496 | 497 | run: check-prereqs run-server run-client ## Runs the server and webapp. 498 | 499 | run-fullmap: run-server run-client ## Legacy alias to run 500 | 501 | stop-server: ## Stops the server. 502 | @echo Stopping mattermost 503 | 504 | ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64") 505 | wmic process where "Caption='go.exe' and CommandLine like '%go.exe run%'" call terminate 506 | wmic process where "Caption='mattermost.exe' and CommandLine like '%go-build%'" call terminate 507 | else 508 | @for PID in $$(ps -ef | grep "[g]o run" | grep "mattermost" | awk '{ print $$2 }'); do \ 509 | echo stopping go $$PID; \ 510 | kill $$PID; \ 511 | done 512 | @for PID in $$(ps -ef | grep "[g]o-build" | grep "mattermost" | awk '{ print $$2 }'); do \ 513 | echo stopping mattermost $$PID; \ 514 | kill $$PID; \ 515 | done 516 | endif 517 | 518 | stop-client: ## Stops the webapp. 519 | @echo Stopping mattermost client 520 | 521 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) stop 522 | 523 | stop: stop-server stop-client stop-docker ## Stops server, client and the docker compose. 524 | 525 | restart: restart-server restart-client ## Restarts the server and webapp. 526 | 527 | restart-server: | stop-server run-server ## Restarts the mattermost server to pick up development change. 528 | 529 | restart-haserver: 530 | @echo Restarting mattermost in an HA topology 531 | 532 | docker-compose restart follower2 533 | docker-compose restart follower 534 | docker-compose restart leader 535 | docker-compose restart haproxy 536 | 537 | restart-client: | stop-client run-client ## Restarts the webapp. 538 | 539 | run-job-server: ## Runs the background job server. 540 | @echo Running job server for development 541 | $(GO) run $(GOFLAGS) -ldflags '$(LDFLAGS)' $(PLATFORM_FILES) jobserver & 542 | 543 | config-ldap: ## Configures LDAP. 544 | @echo Setting up configuration for local LDAP 545 | 546 | @sed -i'' -e 's|"LdapServer": ".*"|"LdapServer": "localhost"|g' config/config.json 547 | @sed -i'' -e 's|"BaseDN": ".*"|"BaseDN": "dc=mm,dc=test,dc=com"|g' config/config.json 548 | @sed -i'' -e 's|"BindUsername": ".*"|"BindUsername": "cn=admin,dc=mm,dc=test,dc=com"|g' config/config.json 549 | @sed -i'' -e 's|"BindPassword": ".*"|"BindPassword": "mostest"|g' config/config.json 550 | @sed -i'' -e 's|"FirstNameAttribute": ".*"|"FirstNameAttribute": "cn"|g' config/config.json 551 | @sed -i'' -e 's|"LastNameAttribute": ".*"|"LastNameAttribute": "sn"|g' config/config.json 552 | @sed -i'' -e 's|"NicknameAttribute": ".*"|"NicknameAttribute": "cn"|g' config/config.json 553 | @sed -i'' -e 's|"EmailAttribute": ".*"|"EmailAttribute": "mail"|g' config/config.json 554 | @sed -i'' -e 's|"UsernameAttribute": ".*"|"UsernameAttribute": "uid"|g' config/config.json 555 | @sed -i'' -e 's|"IdAttribute": ".*"|"IdAttribute": "uid"|g' config/config.json 556 | @sed -i'' -e 's|"LoginIdAttribute": ".*"|"LoginIdAttribute": "uid"|g' config/config.json 557 | @sed -i'' -e 's|"GroupDisplayNameAttribute": ".*"|"GroupDisplayNameAttribute": "cn"|g' config/config.json 558 | @sed -i'' -e 's|"GroupIdAttribute": ".*"|"GroupIdAttribute": "entryUUID"|g' config/config.json 559 | 560 | config-reset: ## Resets the config/config.json file to the default. 561 | @echo Resetting configuration to default 562 | rm -f config/config.json 563 | OUTPUT_CONFIG=$(PWD)/config/config.json $(GO) $(GOFLAGS) run ./scripts/config_generator 564 | 565 | diff-config: ## Compares default configuration between two mattermost versions 566 | @./scripts/diff-config.sh 567 | 568 | clean: stop-docker ## Clean up everything except persistant server data. 569 | @echo Cleaning 570 | 571 | rm -Rf $(DIST_ROOT) 572 | $(GO) clean $(GOFLAGS) -i ./... 573 | 574 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) clean 575 | 576 | find . -type d -name data -not -path './vendor/*' | xargs rm -rf 577 | rm -rf logs 578 | 579 | rm -f mattermost.log 580 | rm -f mattermost.log.jsonl 581 | rm -f npm-debug.log 582 | rm -f .prepare-go 583 | rm -f enterprise 584 | rm -f cover.out 585 | rm -f ecover.out 586 | rm -f *.out 587 | rm -f *.test 588 | rm -f imports/imports.go 589 | rm -f cmd/mattermost/cprofile*.out 590 | 591 | nuke: clean clean-docker ## Clean plus removes persistent server data. 592 | @echo BOOM 593 | 594 | rm -rf data 595 | 596 | setup-mac: ## Adds macOS hosts entries for Docker. 597 | echo $$(boot2docker ip 2> /dev/null) dockerhost | sudo tee -a /etc/hosts 598 | 599 | update-dependencies: ## Uses go get -u to update all the dependencies while holding back any that require it. 600 | @echo Updating Dependencies 601 | 602 | # Update all dependencies (does not update across major versions) 603 | $(GO) get -u ./... 604 | 605 | # Tidy up 606 | $(GO) mod tidy 607 | 608 | # Copy everything to vendor directory 609 | $(GO) mod vendor 610 | 611 | # Tidy up 612 | $(GO) mod tidy 613 | 614 | vet: ## Run mattermost go vet specific checks 615 | $(GO) install github.com/mattermost/mattermost-govet/v2@new 616 | @VET_CMD="-license -structuredLogging -inconsistentReceiverName -inconsistentReceiverName.ignore=session_serial_gen.go,team_member_serial_gen.go,user_serial_gen.go -emptyStrCmp -tFatal -configtelemetry -errorAssertions"; \ 617 | if ! [ -z "${MM_VET_OPENSPEC_PATH}" ] && [ -f "${MM_VET_OPENSPEC_PATH}" ]; then \ 618 | VET_CMD="$$VET_CMD -openApiSync -openApiSync.spec=$$MM_VET_OPENSPEC_PATH"; \ 619 | else \ 620 | echo "MM_VET_OPENSPEC_PATH not set or spec yaml path in it is incorrect. Skipping API check"; \ 621 | fi; \ 622 | $(GO) vet -vettool=$(GOBIN)/mattermost-govet $$VET_CMD ./... 623 | ifeq ($(BUILD_ENTERPRISE_READY),true) 624 | ifneq ($(MM_NO_ENTERPRISE_LINT),true) 625 | $(GO) vet -vettool=$(GOBIN)/mattermost-govet -enterpriseLicense -structuredLogging -tFatal ./enterprise/... 626 | endif 627 | endif 628 | 629 | gen-serialized: ## Generates serialization methods for hot structs 630 | # This tool only works at a file level, not at a package level. 631 | # There will be some warnings about "unresolved identifiers", 632 | # but that is because of the above problem. Since we are generating 633 | # methods for all the relevant files at a package level, all 634 | # identifiers will be resolved. An alternative to remove the warnings 635 | # would be to temporarily move all the structs to the same file, 636 | # but that involves a lot of manual work. 637 | $(GO) get -modfile=go.tools.mod github.com/tinylib/msgp 638 | $(GOBIN)/msgp -file=./model/session.go -tests=false -o=./model/session_serial_gen.go 639 | $(GOBIN)/msgp -file=./model/user.go -tests=false -o=./model/user_serial_gen.go 640 | $(GOBIN)/msgp -file=./model/team_member.go -tests=false -o=./model/team_member_serial_gen.go 641 | 642 | todo: ## Display TODO and FIXME items in the source code. 643 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime TODO 644 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime XXX 645 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime FIXME 646 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime "FIX ME" 647 | ifeq ($(BUILD_ENTERPRISE_READY),true) 648 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime TODO enterprise/ 649 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime XXX enterprise/ 650 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime FIXME enterprise/ 651 | @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime "FIX ME" enterprise/ 652 | endif 653 | 654 | ## Help documentatin à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 655 | help: 656 | @grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' ./Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 657 | @echo 658 | @echo You can modify the default settings for this Makefile creating a file config.mk based on the default-config.mk 659 | @echo 660 | -------------------------------------------------------------------------------- /examples/server/matterbuild.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | runner: 3 | id: make 4 | params: ["build-cmd", "package"] 5 | #secrets: 6 | # - name: TEST_SECRET 7 | env: 8 | - var: PLUGIN_STORE_URL 9 | value: https://plugins-store.test.mattermost.com/release 10 | - var: MM_PLUGIN_ANTIVIRUS 11 | value: mattermost-plugin-antivirus-v0.1.2 12 | - var: MM_PLUGIN_AUTLOINK 13 | value: mattermost-plugin-autolink-v1.2.2 14 | - var: MM_PLUGIN_AWS_SNS 15 | value: mattermost-plugin-aws-SNS-v1.2.0 16 | - var: MM_PLUGIN_CHANNEL_EXPORT 17 | value: mattermost-plugin-channel-export-v1.0.0 18 | - var: MM_PLUGIN_CUSTOM_ATTRS 19 | value: mattermost-plugin-custom-attributes-v1.3.0 20 | - var: MM_PLUGIN_GITHUB 21 | value: mattermost-plugin-github-v2.0.1 22 | - var: MM_PLUGIN_GITLAB 23 | value: mattermost-plugin-gitlab-v1.3.0 24 | - var: MM_PLUGIN_PLAYBOOKS 25 | value: mattermost-plugin-playbooks-v1.22.1 26 | - var: MM_PLUGIN_JENKINS 27 | value: mattermost-plugin-jenkins-v1.1.0 28 | - var: MM_PLUGIN_JIRA 29 | value: mattermost-plugin-jira-v2.4.0 30 | - var: MM_PLUGIN_NPS 31 | value: mattermost-plugin-nps-v1.1.0 32 | - var: MM_PLUGIN_WELCOMEBOT 33 | value: mattermost-plugin-welcomebot-v1.2.0 34 | - var: MM_PLUGIN_ZOOM 35 | value: mattermost-plugin-zoom-v1.5.0 36 | - var: MM_PLUGIN_FOCALBOARD 37 | value: focalboard-v0.11.0 38 | #replacements: 39 | # - paths: [mattermost-server/app/server.go] 40 | # tag: "$SENTRY_DSN" 41 | # value: "sentry-dsn-value" 42 | # - paths: [mattermost-server/services/telemetry/telemetry.go] 43 | # tag: "$RUDDER_KEY_LIVE" 44 | # value: "rudder-key-live" 45 | # - paths: [mattermost-server/services/telemetry/telemetry.go] 46 | # tag: "$RUDDER_DATAPLANE_URL" 47 | # value: "rudder-dataplane-url" 48 | # valueFrom: 49 | # secret: TEST_SECRET 50 | artifacts: 51 | destination: s3://mattermost-development-test/build-test-server/ 52 | files: 53 | - "dist/mattermost-team-linux-amd64.tar.gz" 54 | - "dist/mattermost-team-linux-arm64.tar.gz" 55 | - "dist/mattermost-team-osx-amd64.tar.gz" 56 | - "dist/mattermost-team-osx-arm64.tar.gz" 57 | - "dist/mattermost-team-windows-amd64.zip" 58 | # images: ["index.docker.io/mattermost/mm-te-test:test"] 59 | #transfers: 60 | # - source: ["mattermost-webapp.tar.gz"] 61 | # destination: s3://bucket1/dir/subdir/ 62 | # - source: ["mmctl", "mmctl.sha512"] 63 | # destination: s3://bucket2/projectname/dir/ 64 | materials: 65 | #- uri: "s3://mattermost-development-test/build-test/" 66 | # digest: 67 | # sha1: e97447134cd650ee9f9da5d705a06d3c548d3d6c 68 | ## MMBUILD_STAGING_PATH here will come from the previous run of the webapp build 69 | ## For testing, try: export MMBUILD_STAGING_PATH=133e9fe20423cc76a3ee9da69b48fe1a4bb4d3d8f1180f48b1c6dc6e164d632c 70 | - uri: s3://mattermost-development-test/build-test/${MMBUILD_STAGING_PATH}/mattermost-webapp.tar.gz 71 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ANTIVIRUS}-linux-amd64.tar.gz 72 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AUTLOINK}-linux-amd64.tar.gz 73 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AWS_SNS}-linux-amd64.tar.gz 74 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CHANNEL_EXPORT}-linux-amd64.tar.gz 75 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CUSTOM_ATTRS}-linux-amd64.tar.gz 76 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITHUB}-linux-amd64.tar.gz 77 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITLAB}-linux-amd64.tar.gz 78 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_PLAYBOOKS}-linux-amd64.tar.gz 79 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JENKINS}-linux-amd64.tar.gz 80 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JIRA}-linux-amd64.tar.gz 81 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_NPS}-linux-amd64.tar.gz 82 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_WELCOMEBOT}-linux-amd64.tar.gz 83 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ZOOM}-linux-amd64.tar.gz 84 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_FOCALBOARD}-linux-amd64.tar.gz 85 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ANTIVIRUS}-osx-amd64.tar.gz 86 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AUTLOINK}-osx-amd64.tar.gz 87 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AWS_SNS}-osx-amd64.tar.gz 88 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CHANNEL_EXPORT}-osx-amd64.tar.gz 89 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CUSTOM_ATTRS}-osx-amd64.tar.gz 90 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITHUB}-osx-amd64.tar.gz 91 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITLAB}-osx-amd64.tar.gz 92 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_PLAYBOOKS}-osx-amd64.tar.gz 93 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JENKINS}-osx-amd64.tar.gz 94 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JIRA}-osx-amd64.tar.gz 95 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_NPS}-osx-amd64.tar.gz 96 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_WELCOMEBOT}-osx-amd64.tar.gz 97 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ZOOM}-osx-amd64.tar.gz 98 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_FOCALBOARD}-osx-amd64.tar.gz 99 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ANTIVIRUS}-windows-amd64.tar.gz 100 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AUTLOINK}-windows-amd64.tar.gz 101 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_AWS_SNS}-windows-amd64.tar.gz 102 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CHANNEL_EXPORT}-windows-amd64.tar.gz 103 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_CUSTOM_ATTRS}-windows-amd64.tar.gz 104 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITHUB}-windows-amd64.tar.gz 105 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_GITLAB}-windows-amd64.tar.gz 106 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_PLAYBOOKS}-windows-amd64.tar.gz 107 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JENKINS}-windows-amd64.tar.gz 108 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_JIRA}-windows-amd64.tar.gz 109 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_NPS}-windows-amd64.tar.gz 110 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_WELCOMEBOT}-windows-amd64.tar.gz 111 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_ZOOM}-windows-amd64.tar.gz 112 | - uri: ${PLUGIN_STORE_URL}/${MM_PLUGIN_FOCALBOARD}-windows-amd64.tar.gz 113 | -------------------------------------------------------------------------------- /examples/server/release.mk: -------------------------------------------------------------------------------- 1 | dist: | check-style test package 2 | 3 | build-linux: 4 | @echo Build Linux amd64 5 | ifeq ($(BUILDER_GOOS_GOARCH),"linux_amd64") 6 | env GOOS=linux GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 7 | else 8 | mkdir -p $(GOBIN)/linux_amd64 9 | env GOOS=linux GOARCH=amd64 $(GO) build -o $(GOBIN)/linux_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 10 | endif 11 | @echo Build Linux arm64 12 | ifeq ($(BUILDER_GOOS_GOARCH),"linux_arm64") 13 | env GOOS=linux GOARCH=arm64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 14 | else 15 | mkdir -p $(GOBIN)/linux_arm64 16 | env GOOS=linux GOARCH=arm64 $(GO) build -o $(GOBIN)/linux_arm64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 17 | endif 18 | 19 | build-osx: 20 | @echo Build OSX amd64 21 | ifeq ($(BUILDER_GOOS_GOARCH),"darwin_amd64") 22 | env GOOS=darwin GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 23 | else 24 | mkdir -p $(GOBIN)/darwin_amd64 25 | env GOOS=darwin GOARCH=amd64 $(GO) build -o $(GOBIN)/darwin_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 26 | endif 27 | @echo Build OSX arm64 28 | ifeq ($(BUILDER_GOOS_GOARCH),"darwin_arm64") 29 | env GOOS=darwin GOARCH=arm64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 30 | else 31 | mkdir -p $(GOBIN)/darwin_arm64 32 | env GOOS=darwin GOARCH=arm64 $(GO) build -o $(GOBIN)/darwin_arm64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 33 | endif 34 | 35 | build-windows: 36 | @echo Build Windows amd64 37 | ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64") 38 | env GOOS=windows GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 39 | else 40 | mkdir -p $(GOBIN)/windows_amd64 41 | env GOOS=windows GOARCH=amd64 $(GO) build -o $(GOBIN)/windows_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./... 42 | endif 43 | 44 | build-cmd-linux: 45 | @echo Build CMD Linux amd64 46 | ifeq ($(BUILDER_GOOS_GOARCH),"linux_amd64") 47 | env GOOS=linux GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 48 | else 49 | mkdir -p $(GOBIN)/linux_amd64 50 | env GOOS=linux GOARCH=amd64 $(GO) build -o $(GOBIN)/linux_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 51 | endif 52 | @echo Build CMD Linux arm64 53 | ifeq ($(BUILDER_GOOS_GOARCH),"linux_arm64") 54 | env GOOS=linux GOARCH=arm64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 55 | else 56 | mkdir -p $(GOBIN)/linux_arm64 57 | env GOOS=linux GOARCH=arm64 $(GO) build -o $(GOBIN)/linux_arm64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 58 | endif 59 | 60 | build-cmd-osx: 61 | @echo Build CMD OSX amd64 62 | ifeq ($(BUILDER_GOOS_GOARCH),"darwin_amd64") 63 | env GOOS=darwin GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 64 | else 65 | mkdir -p $(GOBIN)/darwin_amd64 66 | env GOOS=darwin GOARCH=amd64 $(GO) build -o $(GOBIN)/darwin_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 67 | endif 68 | @echo Build CMD OSX arm64 69 | ifeq ($(BUILDER_GOOS_GOARCH),"darwin_arm64") 70 | env GOOS=darwin GOARCH=arm64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 71 | else 72 | mkdir -p $(GOBIN)/darwin_arm64 73 | env GOOS=darwin GOARCH=arm64 $(GO) build -o $(GOBIN)/darwin_arm64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 74 | endif 75 | 76 | build-cmd-windows: 77 | @echo Build CMD Windows amd64 78 | ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64") 79 | env GOOS=windows GOARCH=amd64 $(GO) build -o $(GOBIN) $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 80 | else 81 | mkdir -p $(GOBIN)/windows_amd64 82 | env GOOS=windows GOARCH=amd64 $(GO) build -o $(GOBIN)/windows_amd64 $(GOFLAGS) -trimpath -ldflags '$(LDFLAGS)' ./cmd/... 83 | endif 84 | 85 | build: build-linux build-windows build-osx 86 | 87 | build-cmd: build-cmd-linux build-cmd-windows build-cmd-osx 88 | 89 | build-client: 90 | @echo Building mattermost web app 91 | 92 | cd $(BUILD_WEBAPP_DIR) && $(MAKE) build 93 | 94 | package-prep: 95 | @ echo Packaging mattermost 96 | @# Remove any old files 97 | rm -Rf $(DIST_ROOT) 98 | 99 | @# Resource directories 100 | mkdir -p $(DIST_PATH)/config 101 | cp -L config/README.md $(DIST_PATH)/config 102 | OUTPUT_CONFIG=$(PWD)/$(DIST_PATH)/config/config.json go run ./scripts/config_generator 103 | cp -RL fonts $(DIST_PATH) 104 | cp -RL templates $(DIST_PATH) 105 | rm -rf $(DIST_PATH)/templates/*.mjml $(DIST_PATH)/templates/partials/ 106 | cp -RL i18n $(DIST_PATH) 107 | 108 | @# Disable developer settings 109 | sed -i'' -e 's|"ConsoleLevel": "DEBUG"|"ConsoleLevel": "INFO"|g' $(DIST_PATH)/config/config.json 110 | sed -i'' -e 's|"SiteURL": "http://localhost:8065"|"SiteURL": ""|g' $(DIST_PATH)/config/config.json 111 | 112 | @# Reset email sending to original configuration 113 | sed -i'' -e 's|"SendEmailNotifications": true,|"SendEmailNotifications": false,|g' $(DIST_PATH)/config/config.json 114 | sed -i'' -e 's|"FeedbackEmail": "test@example.com",|"FeedbackEmail": "",|g' $(DIST_PATH)/config/config.json 115 | sed -i'' -e 's|"ReplyToAddress": "test@example.com",|"ReplyToAddress": "",|g' $(DIST_PATH)/config/config.json 116 | sed -i'' -e 's|"SMTPServer": "localhost",|"SMTPServer": "",|g' $(DIST_PATH)/config/config.json 117 | sed -i'' -e 's|"SMTPPort": "2500",|"SMTPPort": "",|g' $(DIST_PATH)/config/config.json 118 | chmod 600 $(DIST_PATH)/config/config.json 119 | 120 | @# Package webapp 121 | mkdir -p $(DIST_PATH)/client 122 | cp -RL $(BUILD_WEBAPP_DIR)/mattermost-webapp.tar.gz $(DIST_PATH)/client 123 | 124 | @# Help files 125 | ifeq ($(BUILD_ENTERPRISE_READY),true) 126 | cp $(BUILD_ENTERPRISE_DIR)/ENTERPRISE-EDITION-LICENSE.txt $(DIST_PATH) 127 | cp -L $(BUILD_ENTERPRISE_DIR)/cloud/config/cloud_defaults.json $(DIST_PATH)/config 128 | else 129 | cp build/MIT-COMPILED-LICENSE.md $(DIST_PATH) 130 | endif 131 | cp NOTICE.txt $(DIST_PATH) 132 | cp README.md $(DIST_PATH) 133 | if [ -f ../manifest.txt ]; then \ 134 | cp ../manifest.txt $(DIST_PATH); \ 135 | fi 136 | 137 | @# Import Mattermost plugin public key 138 | gpg --import build/plugin-production-public-key.gpg 139 | 140 | @# Download prepackaged plugins 141 | mkdir -p tmpprepackaged 142 | @cd tmpprepackaged && for plugin_package in $(PLUGIN_PACKAGES) ; do \ 143 | for ARCH in "osx-amd64" "windows-amd64" "linux-amd64" ; do \ 144 | # curl -f -O -L https://plugins-store.test.mattermost.com/release/$$plugin_package-$$ARCH.tar.gz; \ 145 | curl -f -O -L https://plugins-store.test.mattermost.com/release/$$plugin_package-$$ARCH.tar.gz.sig; \ 146 | done; \ 147 | done 148 | 149 | package-general: 150 | @# Create needed directories 151 | mkdir -p $(DIST_PATH_GENERIC)/bin 152 | mkdir -p $(DIST_PATH_GENERIC)/logs 153 | mkdir -p $(DIST_PATH_GENERIC)/prepackaged_plugins 154 | 155 | @# Copy binary 156 | ifeq ($(BUILDER_GOOS_GOARCH),"$(CURRENT_PACKAGE_ARCH)") 157 | cp $(GOBIN)/$(MM_BIN_NAME) $(DIST_PATH_GENERIC)/bin # from native bin dir, not cross-compiled 158 | else 159 | cp $(GOBIN)/$(CURRENT_PACKAGE_ARCH)/$(MM_BIN_NAME) $(DIST_PATH_GENERIC)/bin # from cross-compiled bin dir 160 | endif 161 | 162 | #Download MMCTL for $(MMCTL_PLATFORM) 163 | scripts/download_mmctl_release.sh $(MMCTL_PLATFORM) $(DIST_PATH_GENERIC)/bin 164 | 165 | ifeq ("darwin_arm64","$(CURRENT_PACKAGE_ARCH)") 166 | echo "No plugins yet for $(CURRENT_PACKAGE_ARCH) platform, skipping..." 167 | else ifeq ("linux_arm64","$(CURRENT_PACKAGE_ARCH)") 168 | echo "No plugins yet for $(CURRENT_PACKAGE_ARCH) platform, skipping..." 169 | else 170 | @# Prepackage plugins 171 | @for plugin_package in $(PLUGIN_PACKAGES) ; do \ 172 | ARCH=$(PLUGIN_ARCH); \ 173 | cp $(MMBUILD_MATERIALS_DIR)/$$plugin_package-$$ARCH.tar.gz $(DIST_PATH_GENERIC)/prepackaged_plugins; \ 174 | cp tmpprepackaged/$$plugin_package-$$ARCH.tar.gz.sig $(DIST_PATH_GENERIC)/prepackaged_plugins; \ 175 | HAS_ARCH=`tar -tf $(DIST_PATH_GENERIC)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz | grep -oE "dist/plugin-.*"`; \ 176 | if [ "$$HAS_ARCH" != "dist/plugin-$(subst _,-,$(CURRENT_PACKAGE_ARCH))" ]; then \ 177 | echo "Contains $$HAS_ARCH in $$plugin_package-$$ARCH.tar.gz but needs dist/plugin-$(subst _,-,$(CURRENT_PACKAGE_ARCH))"; \ 178 | exit 1; \ 179 | fi; \ 180 | gpg --verify $(DIST_PATH_GENERIC)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz.sig $(DIST_PATH_GENERIC)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz; \ 181 | if [ $$? -ne 0 ]; then \ 182 | echo "Failed to verify $$plugin_package-$$ARCH.tar.gz|$$plugin_package-$$ARCH.tar.gz.sig"; \ 183 | exit 1; \ 184 | fi; \ 185 | done 186 | endif 187 | 188 | package-osx-amd64: package-prep 189 | DIST_PATH_GENERIC=$(DIST_PATH_OSX_AMD64) CURRENT_PACKAGE_ARCH=darwin_amd64 PLUGIN_ARCH=osx-amd64 MMCTL_PLATFORM="Darwin-AMD64" MM_BIN_NAME=mattermost $(MAKE) package-general 190 | @# Package 191 | tar -C $(DIST_PATH_OSX_AMD64)/.. -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-osx-amd64.tar.gz mattermost ../mattermost 192 | @# Cleanup 193 | rm -rf $(DIST_ROOT)/osx_amd64 194 | 195 | package-osx-arm64: package-prep 196 | DIST_PATH_GENERIC=$(DIST_PATH_OSX_ARM64) CURRENT_PACKAGE_ARCH=darwin_arm64 PLUGIN_ARCH=osx-arm64 MMCTL_PLATFORM="Darwin-ARM64" MM_BIN_NAME=mattermost $(MAKE) package-general 197 | @# Package 198 | tar -C $(DIST_PATH_OSX_ARM64)/.. -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-osx-arm64.tar.gz mattermost ../mattermost 199 | @# Cleanup 200 | rm -rf $(DIST_ROOT)/osx_arm64 201 | 202 | package-osx: package-osx-amd64 package-osx-arm64 203 | 204 | package-linux-amd64: package-prep 205 | DIST_PATH_GENERIC=$(DIST_PATH_LIN_AMD64) CURRENT_PACKAGE_ARCH=linux_amd64 PLUGIN_ARCH=linux-amd64 MMCTL_PLATFORM="Linux-AMD64" MM_BIN_NAME=mattermost $(MAKE) package-general 206 | @# Package 207 | tar -C $(DIST_PATH_LIN_AMD64)/.. -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-linux-amd64.tar.gz mattermost ../mattermost 208 | @# Cleanup 209 | rm -rf $(DIST_ROOT)/linux_amd64 210 | 211 | package-linux-arm64: package-prep 212 | DIST_PATH_GENERIC=$(DIST_PATH_LIN_ARM64) CURRENT_PACKAGE_ARCH=linux_arm64 PLUGIN_ARCH=linux-arm64 MMCTL_PLATFORM="Linux-ARM64" MM_BIN_NAME=mattermost $(MAKE) package-general 213 | @# Package 214 | tar -C $(DIST_PATH_LIN_ARM64)/.. -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-linux-arm64.tar.gz mattermost ../mattermost 215 | @# Cleanup 216 | rm -rf $(DIST_ROOT)/linux_arm64 217 | 218 | package-linux: package-linux-amd64 package-linux-arm64 219 | 220 | package-windows: package-prep 221 | @# Create needed directories 222 | mkdir -p $(DIST_PATH_WIN)/bin 223 | mkdir -p $(DIST_PATH_WIN)/logs 224 | mkdir -p $(DIST_PATH_WIN)/prepackaged_plugins 225 | 226 | @# Copy binary 227 | ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64") 228 | cp $(GOBIN)/mattermost.exe $(DIST_PATH_WIN)/bin # from native bin dir, not cross-compiled 229 | else 230 | cp $(GOBIN)/windows_amd64/mattermost.exe $(DIST_PATH_WIN)/bin # from cross-compiled bin dir 231 | endif 232 | #Download MMCTL for Windows 233 | scripts/download_mmctl_release.sh "Windows" $(DIST_PATH_WIN)/bin 234 | @# Prepackage plugins 235 | @for plugin_package in $(PLUGIN_PACKAGES) ; do \ 236 | ARCH="windows-amd64"; \ 237 | cp $(MMBUILD_MATERIALS_DIR)/$$plugin_package-$$ARCH.tar.gz $(DIST_PATH_WIN)/prepackaged_plugins; \ 238 | cp tmpprepackaged/$$plugin_package-$$ARCH.tar.gz.sig $(DIST_PATH_WIN)/prepackaged_plugins; \ 239 | HAS_ARCH=`tar -tf $(DIST_PATH_WIN)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz | grep -oE "dist/plugin-.*"`; \ 240 | if [ "$$HAS_ARCH" != "dist/plugin-windows-amd64.exe" ]; then \ 241 | echo "Contains $$HAS_ARCH in $$plugin_package-$$ARCH.tar.gz but needs dist/plugin-windows-amd64.exe"; \ 242 | exit 1; \ 243 | fi; \ 244 | gpg --verify $(DIST_PATH_WIN)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz.sig $(DIST_PATH_WIN)/prepackaged_plugins/$$plugin_package-$$ARCH.tar.gz; \ 245 | if [ $$? -ne 0 ]; then \ 246 | echo "Failed to verify $$plugin_package-$$ARCH.tar.gz|$$plugin_package-$$ARCH.tar.gz.sig"; \ 247 | exit 1; \ 248 | fi; \ 249 | done 250 | @# Package 251 | cd $(DIST_PATH_WIN)/.. && zip -9 -r -q -l ../mattermost-$(BUILD_TYPE_NAME)-windows-amd64.zip mattermost ../mattermost && cd ../.. 252 | @# Cleanup 253 | rm -rf $(DIST_ROOT)/windows 254 | 255 | package: package-osx package-linux package-windows 256 | rm -rf tmpprepackaged 257 | rm -rf $(DIST_PATH) 258 | -------------------------------------------------------------------------------- /examples/webapp/README.md: -------------------------------------------------------------------------------- 1 | # Webapp example 2 | 3 | This directory contains the sample webapp buildconfig to run 4 | the buildsystem in the webapp repo. This is still WIP but it is the 5 | foundation for the new build configiuration that will eventaully run the 6 | build. 7 | -------------------------------------------------------------------------------- /examples/webapp/matterbuild.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | runner: 3 | id: make 4 | params: ["package"] 5 | #secrets: 6 | # - name: TEST_SECRET 7 | #env: 8 | # - var: COMMIT_SHA 9 | # value: b739074e0260def700eb13b2aa6091cae9366327 10 | # - var: COMMIT_WITHOUT_SHA 11 | #replacements: 12 | # - paths: [code.go] 13 | # tag: placeholder 14 | # valueFrom: 15 | # secret: TEST_SECRET 16 | artifacts: 17 | destination: s3://mattermost-development-test/build-test/ 18 | files: ["mattermost-webapp.tar.gz"] 19 | # images: ["index.docker.io/mattermost/mm-te-test:test"] 20 | #transfers: 21 | # - source: ["mattermost-webapp.tar.gz"] 22 | # destination: s3://bucket1/dir/subdir/ 23 | # - source: ["mmctl", "mmctl.sha512"] 24 | # destination: s3://bucket2/projectname/dir/ 25 | #materials: 26 | # - source: "git+https://github.com/foo/bar.git" 27 | # digest: 28 | # sha1: e97447134cd650ee9f9da5d705a06d3c548d3d6c 29 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mattermost/builder 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/mattermost/cicd-sdk v0.0.0-20211231145739-f7c6615b5fba 7 | github.com/pkg/errors v0.9.1 8 | github.com/sirupsen/logrus v1.8.1 9 | github.com/spf13/cobra v1.3.0 10 | ) 11 | 12 | require ( 13 | github.com/Microsoft/go-winio v0.5.1 // indirect 14 | github.com/ProtonMail/go-crypto v0.0.0-20211221144345-a4f6767435ab // indirect 15 | github.com/acomagu/bufpipe v1.0.3 // indirect 16 | github.com/aws/aws-sdk-go v1.42.25 // indirect 17 | github.com/blang/semver v3.5.1+incompatible // indirect 18 | github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/docker/cli v20.10.12+incompatible // indirect 21 | github.com/docker/distribution v2.7.1+incompatible // indirect 22 | github.com/docker/docker v20.10.12+incompatible // indirect 23 | github.com/docker/docker-credential-helpers v0.6.4 // indirect 24 | github.com/emirpasic/gods v1.12.0 // indirect 25 | github.com/go-git/gcfg v1.5.0 // indirect 26 | github.com/go-git/go-billy/v5 v5.3.1 // indirect 27 | github.com/go-git/go-git/v5 v5.4.2 // indirect 28 | github.com/google/go-containerregistry v0.7.0 // indirect 29 | github.com/google/licenseclassifier/v2 v2.0.0-alpha.1 // indirect 30 | github.com/google/uuid v1.3.0 // indirect 31 | github.com/imdario/mergo v0.3.12 // indirect 32 | github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf // indirect 33 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 34 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 35 | github.com/jmespath/go-jmespath v0.4.0 // indirect 36 | github.com/kevinburke/ssh_config v1.1.0 // indirect 37 | github.com/klauspost/compress v1.13.6 // indirect 38 | github.com/mitchellh/go-homedir v1.1.0 // indirect 39 | github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect 40 | github.com/opencontainers/go-digest v1.0.0 // indirect 41 | github.com/opencontainers/image-spec v1.0.2 // indirect 42 | github.com/secure-systems-lab/go-securesystemslib v0.3.0 // indirect 43 | github.com/sergi/go-diff v1.2.0 // indirect 44 | github.com/shibumi/go-pathspec v1.3.0 // indirect 45 | github.com/spf13/pflag v1.0.5 // indirect 46 | github.com/vbatts/tar-split v0.11.2 // indirect 47 | github.com/xanzy/ssh-agent v0.3.1 // indirect 48 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect 49 | golang.org/x/mod v0.5.1 // indirect 50 | golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect 51 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 52 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect 53 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 54 | golang.org/x/tools v0.1.8 // indirect 55 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 56 | gopkg.in/warnings.v0 v0.1.2 // indirect 57 | gopkg.in/yaml.v2 v2.4.0 // indirect 58 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 59 | sigs.k8s.io/bom v0.1.1-0.20211228172218-5dc67098b61b // indirect 60 | sigs.k8s.io/release-utils v0.3.0 // indirect 61 | ) 62 | --------------------------------------------------------------------------------