diff options
| -rwxr-xr-x | .buildkite/hooks/post-command | 11 | ||||
| -rwxr-xr-x | .buildkite/steps/ghartifacts.sh | 2 | ||||
| -rw-r--r-- | .github/probot.js | 10 | ||||
| -rw-r--r-- | .golangci.yml | 2 | ||||
| -rw-r--r-- | cmd/authelia-scripts/cmd_docker.go | 165 | ||||
| -rw-r--r-- | cmd/authelia-scripts/const.go | 5 | ||||
| -rw-r--r-- | cmd/authelia-scripts/docker.go | 4 | 
7 files changed, 120 insertions, 79 deletions
diff --git a/.buildkite/hooks/post-command b/.buildkite/hooks/post-command index f83bc9ad2..e03fdab99 100755 --- a/.buildkite/hooks/post-command +++ b/.buildkite/hooks/post-command @@ -37,6 +37,7 @@ fi  if [[ $BUILDKITE_LABEL =~ ":docker: Deploy" ]]; then    docker logout +  docker logout ghcr.io  fi  if [[ $BUILDKITE_LABEL == ":docker: Deploy Manifests" ]] && [[ $BUILDKITE_BRANCH == "master" ]] && [[ $BUILDKITE_PULL_REQUEST == "false" ]]; then @@ -49,6 +50,9 @@ if [[ $BUILDKITE_LABEL == ":docker: Deploy Manifests" ]] && [[ $BUILDKITE_BRANCH    comm -23 <(echo "${dockerbranchtags}") <(echo "${githubbranches}")); do      echo "Removing tag ${BRANCH_TAG}"      curl -fsL --retry 3 -o /dev/null -X "DELETE" -H "Authorization: JWT ${authtoken}" https://hub.docker.com/v2/repositories/authelia/authelia/tags/${BRANCH_TAG}/ +    for GHCR_VERSION in $(curl -fsL --retry 3 -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions | jq --arg tag ${BRANCH_TAG} '.[] | select(.metadata.container.tags[] | contains($tag)) | .id'); do +      curl -fsL --retry 3 -o /dev/null -X "DELETE" -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions/${GHCR_VERSION} +    done    done    echo "--- :docker: Removing tags for merged or closed pull requests"    for PR_TAG in $(dockerprtags=$(curl -fsL --retry 3 -H "Authorization: Bearer ${anontoken}" https://registry-1.docker.io/v2/authelia/authelia/tags/list | jq -r '.tags[] | select(startswith("PR"))' | \ @@ -57,5 +61,12 @@ if [[ $BUILDKITE_LABEL == ":docker: Deploy Manifests" ]] && [[ $BUILDKITE_BRANCH    comm -23 <(echo "${dockerprtags}") <(echo "${githubprs}")); do      echo "Removing tag ${PR_TAG}"      curl -fsL --retry 3 -o /dev/null -X "DELETE" -H "Authorization: JWT ${authtoken}" https://hub.docker.com/v2/repositories/authelia/authelia/tags/${PR_TAG}/ +    for GHCR_VERSION in $(curl -fsL --retry 3 -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions | jq --arg tag ${PR_TAG} '.[] | select(.metadata.container.tags[] | contains($tag)) | .id'); do +      curl -fsL --retry 3 -o /dev/null -X "DELETE" -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions/${GHCR_VERSION} +    done +  done +  echo "--- :docker: Removing empty tags for old images on GHCR" +  for GHCR_VERSION in $(curl -fsL --retry 3 -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions | jq '.[] | select((.metadata.container.tags|length) == 0) | .id'); do +    curl -fsL --retry 3 -o /dev/null -X "DELETE" -H "Authorization: Bearer ${GHCR_PASSWORD}" -H "Accept: application/vnd.github.v3+json" https://api.github.com/orgs/authelia/packages/container/authelia/versions/${GHCR_VERSION}    done  fi
\ No newline at end of file diff --git a/.buildkite/steps/ghartifacts.sh b/.buildkite/steps/ghartifacts.sh index 1f3d44072..5b93eeba8 100755 --- a/.buildkite/steps/ghartifacts.sh +++ b/.buildkite/steps/ghartifacts.sh @@ -13,7 +13,7 @@ do  done  echo "--- :github: Deploy artifacts for release: ${BUILDKITE_TAG}" -hub release create "${BUILDKITE_TAG}" "${artifacts[@]}" -F <(echo -e "${BUILDKITE_TAG}\n$(conventional-changelog -p angular -o /dev/stdout -r 2 | sed -e '1,3d')\n\n### Docker Container\n* \`docker pull authelia/authelia:${BUILDKITE_TAG//v}\`"); EXIT=$? +hub release create "${BUILDKITE_TAG}" "${artifacts[@]}" -F <(echo -e "${BUILDKITE_TAG}\n$(conventional-changelog -p angular -o /dev/stdout -r 2 | sed -e '1,3d')\n\n### Docker Container\n* \`docker pull authelia/authelia:${BUILDKITE_TAG//v}\`\n* \`docker pull ghcr.io/authelia/authelia:${BUILDKITE_TAG//v}\`"); EXIT=$?  if [[ $EXIT == 0 ]];    then diff --git a/.github/probot.js b/.github/probot.js index 8f49a5077..7caf6aab6 100644 --- a/.github/probot.js +++ b/.github/probot.js @@ -13,10 +13,11 @@ on('pull_request.opened')              context.payload.pull_request.head.ref.slice(0, 9) !== 'renovate/'      )      .comment(`## Artifacts -These changes are published for testing on Buildkite and DockerHub. +These changes are published for testing on Buildkite, DockerHub and GitHub Container Registry.  ### Docker Container -* \`docker pull authelia/authelia:{{ pull_request.head.ref }}\``) +* \`docker pull authelia/authelia:{{ pull_request.head.ref }}\` +* \`docker pull ghcr.io/authelia/authelia:{{ pull_request.head.ref }}\``)  // PR commentary for third party based contributions  on('pull_request.opened') @@ -29,7 +30,8 @@ on('pull_request.opened')  You are free to apply the changes if you're comfortable, alternatively you are welcome to ask a team member for advice.  ## Artifacts -These changes once approved by a team member will be published for testing on Buildkite and DockerHub. +These changes once approved by a team member will be published for testing on Buildkite, DockerHub and GitHub Container Registry.  ### Docker Container -* \`docker pull authelia/authelia:PR{{ pull_request.number }}\``)
\ No newline at end of file +* \`docker pull authelia/authelia:PR{{ pull_request.number }}\` +* \`docker pull ghcr.io/authelia/authelia:PR{{ pull_request.number }}\``)
\ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index 251323952..ec2af8df2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -23,8 +23,6 @@ linters:      - goimports      - golint      - gosec -    - interfacer -    - maligned      - misspell      - nolintlint      - prealloc diff --git a/cmd/authelia-scripts/cmd_docker.go b/cmd/authelia-scripts/cmd_docker.go index 2960401cd..63209d1cb 100644 --- a/cmd/authelia-scripts/cmd_docker.go +++ b/cmd/authelia-scripts/cmd_docker.go @@ -23,7 +23,7 @@ var ciPullRequest = os.Getenv("BUILDKITE_PULL_REQUEST")  var ciTag = os.Getenv("BUILDKITE_TAG")  var dockerTags = regexp.MustCompile(`v(?P<Patch>(?P<Minor>(?P<Major>\d+)\.\d+)\.\d+.*)`)  var ignoredSuffixes = regexp.MustCompile("alpha|beta") -var publicRepo = regexp.MustCompile(`.*\:.*`) +var publicRepo = regexp.MustCompile(`.*:.*`)  var tags = dockerTags.FindStringSubmatch(ciTag)  func init() { @@ -144,30 +144,39 @@ var DockerManifestCmd = &cobra.Command{  	},  } -func login(docker *Docker) { -	username := os.Getenv("DOCKER_USERNAME") -	password := os.Getenv("DOCKER_PASSWORD") +func login(docker *Docker, registry string) { +	username := "" +	password := "" + +	switch registry { +	case dockerhub: +		username = os.Getenv("DOCKER_USERNAME") +		password = os.Getenv("DOCKER_PASSWORD") +	case ghcr: +		username = os.Getenv("GHCR_USERNAME") +		password = os.Getenv("GHCR_PASSWORD") +	}  	if username == "" { -		log.Fatal(errors.New("DOCKER_USERNAME is empty")) +		log.Fatal(errors.New("DOCKER_USERNAME/GHCR_USERNAME is empty"))  	}  	if password == "" { -		log.Fatal(errors.New("DOCKER_PASSWORD is empty")) +		log.Fatal(errors.New("DOCKER_PASSWORD/GHCR_PASSWORD is empty"))  	} -	log.Infof("Login to Docker Hub as %s", username) -	err := docker.Login(username, password) +	log.Infof("Login to %s as %s", registry, username) +	err := docker.Login(username, password, registry)  	if err != nil { -		log.Fatal("Login to Docker Hub failed", err) +		log.Fatalf("Login to %s failed: %s", registry, err)  	}  } -func deploy(docker *Docker, tag string) { -	imageWithTag := DockerImageName + ":" + tag +func deploy(docker *Docker, tag, registry string) { +	imageWithTag := registry + "/" + DockerImageName + ":" + tag -	log.Infof("Docker image %s will be deployed on Docker Hub", imageWithTag) +	log.Infof("Docker image %s will be deployed on %s", imageWithTag, registry)  	if err := docker.Tag(DockerImageName, imageWithTag); err != nil {  		log.Fatal(err) @@ -178,10 +187,10 @@ func deploy(docker *Docker, tag string) {  	}  } -func deployManifest(docker *Docker, tag string, amd64tag string, arm32v7tag string, arm64v8tag string) { -	dockerImagePrefix := DockerImageName + ":" +func deployManifest(docker *Docker, tag, amd64tag, arm32v7tag, arm64v8tag, registry string) { +	dockerImagePrefix := registry + "/" + DockerImageName + ":" -	log.Infof("Docker manifest %s%s will be deployed on Docker Hub", dockerImagePrefix, tag) +	log.Infof("Docker manifest %s%s will be deployed on %s", dockerImagePrefix, tag, registry)  	err := docker.Manifest(dockerImagePrefix+tag, dockerImagePrefix+amd64tag, dockerImagePrefix+arm32v7tag, dockerImagePrefix+arm64v8tag) @@ -190,11 +199,14 @@ func deployManifest(docker *Docker, tag string, amd64tag string, arm32v7tag stri  	}  	tags := []string{amd64tag, arm32v7tag, arm64v8tag} -	for _, t := range tags { -		log.Infof("Docker removing tag for %s%s on Docker Hub", dockerImagePrefix, t) -		if err := docker.CleanTag(t); err != nil { -			panic(err) +	if registry == dockerhub { +		for _, t := range tags { +			log.Infof("Docker removing tag for %s%s on Docker Hub", dockerImagePrefix, t) + +			if err := docker.CleanTag(t); err != nil { +				panic(err) +			}  		}  	}  } @@ -202,68 +214,81 @@ func deployManifest(docker *Docker, tag string, amd64tag string, arm32v7tag stri  func publishDockerImage(arch string) {  	docker := &Docker{} -	switch { -	case ciTag != "": -		if len(tags) == 4 { -			log.Infof("Detected tags: '%s' | '%s' | '%s'", tags[1], tags[2], tags[3]) -			login(docker) -			deploy(docker, tags[1]+"-"+arch) - -			if !ignoredSuffixes.MatchString(ciTag) { -				deploy(docker, tags[2]+"-"+arch) -				deploy(docker, tags[3]+"-"+arch) -				deploy(docker, "latest-"+arch) +	for _, registry := range registries { +		switch { +		case ciTag != "": +			if len(tags) == 4 { +				log.Infof("Detected tags: '%s' | '%s' | '%s'", tags[1], tags[2], tags[3]) +				login(docker, registry) +				deploy(docker, tags[1]+"-"+arch, registry) + +				if !ignoredSuffixes.MatchString(ciTag) { +					deploy(docker, tags[2]+"-"+arch, registry) +					deploy(docker, tags[3]+"-"+arch, registry) +					deploy(docker, "latest-"+arch, registry) +				} +			} else { +				log.Fatal("Docker image will not be published, the specified tag does not conform to the standard")  			} -		} else { -			log.Fatal("Docker image will not be published, the specified tag does not conform to the standard") +		case ciBranch != masterTag && !publicRepo.MatchString(ciBranch): +			login(docker, registry) +			deploy(docker, ciBranch+"-"+arch, registry) +		case ciBranch != masterTag && publicRepo.MatchString(ciBranch): +			login(docker, registry) +			deploy(docker, "PR"+ciPullRequest+"-"+arch, registry) +		case ciBranch == masterTag && ciPullRequest == stringFalse: +			login(docker, registry) +			deploy(docker, "master-"+arch, registry) +		default: +			log.Info("Docker image will not be published")  		} -	case ciBranch != masterTag && !publicRepo.MatchString(ciBranch): -		login(docker) -		deploy(docker, ciBranch+"-"+arch) -	case ciBranch != masterTag && publicRepo.MatchString(ciBranch): -		login(docker) -		deploy(docker, "PR"+ciPullRequest+"-"+arch) -	case ciBranch == masterTag && ciPullRequest == stringFalse: -		login(docker) -		deploy(docker, "master-"+arch) -	default: -		log.Info("Docker image will not be published")  	}  }  func publishDockerManifest() {  	docker := &Docker{} -	switch { -	case ciTag != "": -		if len(tags) == 4 { -			log.Infof("Detected tags: '%s' | '%s' | '%s'", tags[1], tags[2], tags[3]) -			login(docker) -			deployManifest(docker, tags[1], tags[1]+"-amd64", tags[1]+"-arm32v7", tags[1]+"-arm64v8") -			publishDockerReadme(docker) - -			if !ignoredSuffixes.MatchString(ciTag) { -				deployManifest(docker, tags[2], tags[2]+"-amd64", tags[2]+"-arm32v7", tags[2]+"-arm64v8") -				deployManifest(docker, tags[3], tags[3]+"-amd64", tags[3]+"-arm32v7", tags[3]+"-arm64v8") -				deployManifest(docker, "latest", "latest-amd64", "latest-arm32v7", "latest-arm64v8") +	for _, registry := range registries { +		switch { +		case ciTag != "": +			if len(tags) == 4 { +				log.Infof("Detected tags: '%s' | '%s' | '%s'", tags[1], tags[2], tags[3]) +				login(docker, registry) +				deployManifest(docker, tags[1], tags[1]+"-amd64", tags[1]+"-arm32v7", tags[1]+"-arm64v8", registry) + +				if registry == dockerhub { +					publishDockerReadme(docker) +				} + +				if !ignoredSuffixes.MatchString(ciTag) { +					deployManifest(docker, tags[2], tags[2]+"-amd64", tags[2]+"-arm32v7", tags[2]+"-arm64v8", registry) +					deployManifest(docker, tags[3], tags[3]+"-amd64", tags[3]+"-arm32v7", tags[3]+"-arm64v8", registry) +					deployManifest(docker, "latest", "latest-amd64", "latest-arm32v7", "latest-arm64v8", registry) + +					if registry == dockerhub { +						publishDockerReadme(docker) +						updateMicroBadger(docker) +					} +				} +			} else { +				log.Fatal("Docker manifest will not be published, the specified tag does not conform to the standard") +			} +		case ciBranch != masterTag && !publicRepo.MatchString(ciBranch): +			login(docker, registry) +			deployManifest(docker, ciBranch, ciBranch+"-amd64", ciBranch+"-arm32v7", ciBranch+"-arm64v8", registry) +		case ciBranch != masterTag && publicRepo.MatchString(ciBranch): +			login(docker, registry) +			deployManifest(docker, "PR"+ciPullRequest, "PR"+ciPullRequest+"-amd64", "PR"+ciPullRequest+"-arm32v7", "PR"+ciPullRequest+"-arm64v8", registry) +		case ciBranch == masterTag && ciPullRequest == stringFalse: +			login(docker, registry) +			deployManifest(docker, "master", "master-amd64", "master-arm32v7", "master-arm64v8", registry) + +			if registry == dockerhub {  				publishDockerReadme(docker) -				updateMicroBadger(docker)  			} -		} else { -			log.Fatal("Docker manifest will not be published, the specified tag does not conform to the standard") +		default: +			log.Info("Docker manifest will not be published")  		} -	case ciBranch != masterTag && !publicRepo.MatchString(ciBranch): -		login(docker) -		deployManifest(docker, ciBranch, ciBranch+"-amd64", ciBranch+"-arm32v7", ciBranch+"-arm64v8") -	case ciBranch != masterTag && publicRepo.MatchString(ciBranch): -		login(docker) -		deployManifest(docker, "PR"+ciPullRequest, "PR"+ciPullRequest+"-amd64", "PR"+ciPullRequest+"-arm32v7", "PR"+ciPullRequest+"-arm64v8") -	case ciBranch == masterTag && ciPullRequest == stringFalse: -		login(docker) -		deployManifest(docker, "master", "master-amd64", "master-arm32v7", "master-arm64v8") -		publishDockerReadme(docker) -	default: -		log.Info("Docker manifest will not be published")  	}  } diff --git a/cmd/authelia-scripts/const.go b/cmd/authelia-scripts/const.go index efb83cde0..87b2ed99c 100644 --- a/cmd/authelia-scripts/const.go +++ b/cmd/authelia-scripts/const.go @@ -9,6 +9,11 @@ var DockerImageName = "authelia/authelia"  // IntermediateDockerImageName local name of the docker image.  var IntermediateDockerImageName = "authelia:dist" +var registries = []string{"docker.io", "ghcr.io"} + +const dockerhub = "docker.io" +const ghcr = "ghcr.io" +  const masterTag = "master"  const stringFalse = "false"  const stringTrue = "true" diff --git a/cmd/authelia-scripts/docker.go b/cmd/authelia-scripts/docker.go index 508ed3aa6..10fcc25aa 100644 --- a/cmd/authelia-scripts/docker.go +++ b/cmd/authelia-scripts/docker.go @@ -20,8 +20,8 @@ func (d *Docker) Tag(image, tag string) error {  }  // Login login to the dockerhub registry. -func (d *Docker) Login(username, password string) error { -	return utils.CommandWithStdout("docker", "login", "-u", username, "-p", password).Run() +func (d *Docker) Login(username, password, registry string) error { +	return utils.CommandWithStdout("docker", "login", registry, "-u", username, "-p", password).Run()  }  // Push push a docker image to dockerhub.  | 
