Master Branch
this to me alwasy seemed like something that would take a LOT of time and in the end juts be confusing. THe idea was that we needed something that would allow us to have an exact copy of live. I feel like we didnt' implment the tools below because of the chagnes Larry makes to the artifacts to make them live. Changes he makes MANUALLY by opening files and changing some values. There is proably a difference in the .yml file as well – but we can just put back the values we need to manually- and keep a copy of the correct .yml file to use. From what our discussion was about – there is no refactoring of the – it is a copy with some manual edits to it. Which to me means – we can reverse it – either with these tools below – OR – do we even need them?
was what I thought I would find a first –
BUT we do not need AEBN to make our sites live – is what I discovered.
Currently – DEV (quantox) is whree gitlab lives – it builds the artifact. Then Larry manually makes changes to those file – and move the artifact around. (which is BASICALLY LIKE ME PUTITNG FILES ON THE LIVE SERVER) – which of course is very strssufl or us / them everyone involved. It also ties us to thier team and TO THEIR SCHEDULE. It does not have to be that way. Here’s how you can enhance your deployment pipeline using Nexus or Artifactory for artifact management.
IN ADDITION – we do away with _master branchand all that mess – (the thing that makes makeing sites live take day) bucause if you want to work on the current prod branch – YOU JUST PULL IT DOWN – AND RUN IT like any other branch.
Sonatype Nexus Repository vs JFrog Artifactory
1. Number of Sites and Scale:
• Both tools can handle a dozen sites, but Artifactory might offer better support for larger and more complex environments.
2. Deployment Process (Local => Dev => QA => Prod):
• Artifact Management: Both tools support storing and managing artifacts through different stages.
• Promotion: Artifactory has strong support for artifact promotion workflows which might be beneficial.
3. Configuration Management:
• Both tools can help standardize and automate the manual changes we are making between environment these steps.
4. Integration with GitLab:
• Both tools integrate well with GitLab CI/CD, enabling streamlined build and deployment pipelines.
5. Budget:
• If cost is a significant concern, Nexus might be more budget-friendly.
GitLab does not officially endorse a specific artifact repository, and both Nexus and Artifactory are commonly used with GitLab CI/CD. The choice between the two typically depends on your specific requirements, preferences, and existing infrastructure. Here’s a comparison to help you decide:
JFrog Artifactory
Pros:
• Wide Support: Supports a wide range of package types, including Docker, npm, Maven, NuGet, and more.
• Integration: Integrates well with various CI/CD tools, including GitLab CI/CD.
• Enterprise Features: Offers advanced features such as high availability, multi-site replication, and enterprise-grade security.
• Universal Repository: Can serve as a single source of truth for all types of binary artifacts.
Cons:
• Cost: Enterprise features come with a cost, which might be higher than some alternatives.
• Complexity: The rich feature set can introduce complexity in setup and management.
Sonatype Nexus Repository
Pros:
• Simplicity: Easier to set up and manage for basic use cases.
• Support: Also supports a wide range of package types and formats.
• Cost-Effective: May be more cost-effective for small to medium-sized teams.
• Community Edition: The OSS version is robust and suitable for many common use cases.
Cons:
• Features: Might lack some of the advanced features available in Artifactory’s enterprise editions.
they work with distributed setups
Sonatype Nexus Repository and JFrog Artifactory can work in a distributed setup, including situations where your development team is located remotely and not part of your main server infrastructure. However, there are some considerations to ensure seamless integration and efficient artifact management:
Key Considerations for a Distributed Setup
1. Network Latency and Bandwidth: Ensure there is sufficient bandwidth and low latency between the remote development environment and your artifact repository.
2. Security: Secure access to your artifact repository with proper authentication and encryption (e.g., using HTTPS).
3. Access Management: Ensure appropriate access controls are in place to manage permissions for remote developers.
Using Nexus Repository or Artifactory in a Distributed Setup
1. Network Access
Ensure that your remote development environment can access the artifact repository over the network. This typically involves:
• Public Access: If your artifact repository is accessible over the public internet, ensure it is secured with HTTPS and proper authentication.
• VPN: Use a VPN to securely connect remote environments to your internal network if the repository is hosted within a private network.
2. Setting Up the Artifact Repository
1. Install and Configure Nexus Repository or Artifactory:
• Follow the installation guides for Nexus Repository or Artifactory.
• Configure repositories for different types of artifacts (e.g., npm, Maven, Docker).
2. Secure the Repository:
• Use HTTPS for secure communication.
• Set up user authentication and access controls.
3. Integrate with CI/CD Pipeline
Configure your CI/CD pipeline to interact with the artifact repository. Here’s an example of how to integrate GitLab CI/CD with Nexus Repository:
.gitlab-ci.yml Example:
stages:
- build
- test
- deploy
variables:
NEXUS_URL: "https://nexus.example.com/repository/your-repo"
NEXUS_USER: "your-username"
NEXUS_PASS: "your-password"
ARTIFACT_NAME: "your-project"
build:
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- build/
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- zip -r $ARTIFACT_NAME.zip build/
- curl -u $NEXUS_USER:$NEXUS_PASS --upload-file $ARTIFACT_NAME.zip $NEXUS_URL/$ARTIFACT_NAME.zip
only:
- master
4. Remote Development Environment
Ensure that your remote developers have the necessary tools and configurations to interact with the artifact repository:
1. Access Configuration:
• Provide remote developers with credentials to access the artifact repository.
• Ensure they can access the repository URL (consider using a VPN if the repository is hosted privately).
2. Environment Setup:
• Document the steps required to set up the local development environment to use artifacts from the repository.
• Provide scripts or tools to simplify the setup process.
5. Automate Artifact Promotion
Automate the promotion of artifacts between environments (Dev -> QA -> Prod) using scripts or CI/CD pipelines.
Promotion Script Example:
#!/bin/bash
TARGET_ENV=$1
# Variables
NEXUS_URL="https://nexus.example.com/repository/your-repo"
NEXUS_USER="your-username"
NEXUS_PASS="your-password"
ARTIFACT_NAME="your-project"
# Download the artifact
curl -u $NEXUS_USER:$NEXUS_PASS -O $NEXUS_URL/$ARTIFACT_NAME.zip
# Unzip the artifact
unzip $ARTIFACT_NAME.zip -d /path/to/$TARGET_ENV
# Apply environment-specific configuration
if [ "$TARGET_ENV" == "QA" ]; then
cp config/qa.env /path/to/$TARGET_ENV/.env
elif [ "$TARGET_ENV" == "prod" ]; then
cp config/prod.env /path/to/$TARGET_ENV/.env
fi
# Deploy the artifact to the target environment
# (e.g., copy to the appropriate directory or trigger a deployment script)
Summary
Both Nexus Repository and Artifactory can work in a distributed setup with remote development environments. Key steps include:
• Ensuring network access and security.
• Setting up and securing the artifact repository.
• Integrating with your CI/CD pipeline.
• Configuring remote development environments to access and use the repository.
• Automating artifact promotion between environments.
If your current setup introduces significant delays or complications, it might be beneficial to bring the development environment closer to your main server infrastructure, potentially using a cloud-based solution to centralize and streamline access. However, with proper configuration and tools, a distributed setup can still work effectively.
Sonatype Nexus Repository OSS
Looking at them – Sonatype Nexus Repository OSS/Pro: Start with Nexus Repository OSS. If you need more features, consider upgrading to Nexus Pro. It’s cost-effective and will handle your needs well for a dozen sites.
Using Sonatype Nexus Repository
1. Set Up Nexus Repository:
• Follow the installation guide to set up Nexus.
2. Configure CI/CD in GitLab:
• .gitlab-ci.yml example:
stages:
- build
- test
- deploy
variables:
NEXUS_URL: "https://nexus.example.com/repository/your-repo"
NEXUS_USER: "your-username"
NEXUS_PASS: "your-password"
ARTIFACT_NAME: "your-project"
build:
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- build/
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- zip -r $ARTIFACT_NAME.zip build/
- curl -u $NEXUS_USER:$NEXUS_PASS --upload-file $ARTIFACT_NAME.zip $NEXUS_URL/$ARTIFACT_NAME.zip
only:
- master
Using JFrog Artifactory
1. Set Up Artifactory:
• Follow the installation guide to set up Artifactory.
2. Configure CI/CD in GitLab:
• .gitlab-ci.yml example:
stages:
- build
- test
- deploy
variables:
ARTIFACTORY_URL: "https://artifactory.example.com/artifactory"
ARTIFACTORY_USER: "your-username"
ARTIFACTORY_PASS: "your-password"
ARTIFACT_NAME: "your-project"
build:
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- build/
test:
stage: test
script:
- npm test
deploy:
stage: deploy
script:
- zip -r $ARTIFACT_NAME.zip build/
- curl -u $ARTIFACTORY_USER:$ARTIFACTORY_PASS -T $ARTIFACT_NAME.zip "$ARTIFACTORY_URL/your-repo/$ARTIFACT_NAME.zip"
only:
- master
no more master branch
With this in place –
Steps to Convert an Artifact Back into a Working Local Project
1. Download the Artifact from Nexus
2. Extract the Artifact
3. Set Up the Local Development Environment
4. Install Dependencies
5. Run the Project Locally
Detailed Steps
1. Download the Artifact from Nexus
Use a tool like curl or any HTTP client to download the artifact from Nexus.
Example Command:
curl -u your-username:your-password -O https://nexus.example.com/repository/your-repo/your-artifact.zip
2. Extract the Artifact
Unzip the downloaded artifact to a local directory.
Example Command:
unzip your-artifact.zip -d /path/to/local/project
3. Set Up the Local Development Environment
Navigate to the directory where you extracted the artifact and ensure all necessary configuration files are in place.
Example:
cd /path/to/local/project
then it is the exact same way we work now
doing away with stage / 1 sit with all changes
Overview of the Improved Deployment Process
1. Local Development: Developers push code changes to the repository.
2. CI/CD Pipeline: GitLab CI/CD builds the artifact and stores it in Nexus or Artifactory.
3. Automated Promotion: Artifacts are promoted from development to QA and then to production, with configuration changes managed automatically.
Steps to Implement
1. Set Up Artifact Repository
2. Configure CI/CD Pipeline in GitLab
3. Automate Configuration Changes
4. Automate Artifact Promotion
Step 1: Set Up Artifact Repository
Choose and Set Up a Repository:
• Nexus Repository: Follow the Sonatype Nexus Repository setup guide to install and configure.
• Artifactory: Follow the JFrog Artifactory setup guide to install and configure.
Step 2: Configure CI/CD Pipeline in GitLab
.gitlab-ci.yml:
Addressing the Current Approach
1. Conditional Rendering with
• This approach allows for flexibility but can lead to a cluttered and complex codebase, especially when the number of conditions increases.
• It can make the component harder to read, understand, and maintain.
Using Config.js and React Context
Key Benefits
- Centralized Configuration: All site-specific configurations are centralized in a single file, making it easier to manage site-specific settings and routes and make updates.
- Separation of Concerns / Maintainability: By separating the configuration from the component logic, you make the codebase easier to manage and understand.
- Consistency: Ensures that site-specific logic is applied consistently across different components.
- Scalability / Improved Deployment Workflow: Simplify the deployment process to handle individual site updates more effectively. Adding a new site or modifying an existing one becomes a straightforward task, reducing the risk of introducing bugs.
- Modularity: Each site-specific configuration is defined in a single place, making it easier to update and maintain.
- Use Context or Hooks: Implement React Context or custom hooks to manage shared state and functionality.
By adopting this shared configuration approach, you can simplify the management of multiple sites within a single codebase, reduce complexity, and improve overall development efficiency.
Benefits of Using React Context for Configuration
1. Single Import: You only import the configuration once in the SiteConfigProvider, and it is available throughout the component tree.
2. Cleaner Components: Components are not cluttered with configuration imports and logic, making them cleaner and easier to manage.
3. Dynamic Configurations: You can easily switch configurations based on the current site context.
By using React Context, you can simplify the process of applying site-specific configurations across multiple components without the need for repetitive imports and initializations. This approach also ensures that any changes to the configuration are immediately reflected across all components that consume the context.
Refactoring
Key Points to Address
1. Separate Configurations: Use a configuration-driven approach to manage site-specific settings and routes.
2. Component Separation: Break down large components into smaller, reusable components.
3. Use Context or Hooks: Implement React Context or custom hooks to manage shared state and functionality.
- Improve Deployment Workflow: Simplify the deployment process to handle individual site updates more effectively.
By refactoring the MainDashboardHeader component in this way, you can simplify the handling of site-specific logic and make the overall codebase more maintainable. This should help reduce some of the frustration and improve the workflow for managing multiple sites.
Plan
To implement the React Context configuration approach and refactor your existing codebase, you should consider the following steps:
1. Plan the Changes
1. Identify Common Functionality: Determine the common functionality that should be shared across all sites.
2. Define Site-Specific Configurations: Clearly define what configurations differ between sites.
2. Implement Context-Based Configuration
1. Create the Configuration Context: Set up the React Context for configuration.
2. Refactor Components: Refactor components to use the new context-based configuration.
3. Update Branches
1. Work on Individual Site Branches: Implement and test the changes on individual site branches first.
2. Integrate Changes into the Stage Branch: Once changes are verified on individual site branches, integrate them into the stage branch.
Detailed Steps
1. Create a Main Configuration File:
• Define your site-specific configurations in a config.js file.
The configuration file should ideally be shared if you are maintaining multiple sites within a single codebase but with distinct configurations. This shared configuration file can then be referenced by each site to apply its specific settings. Here’s a practical approach to manage this:
Shared Configuration File
src/config/siteConfig.js (high order on server)
Location: Place the shared configuration file in a common directory that is accessible to all sites. For instance, you could have a config directory at the root of your project.
Example Directory Structure – ALL SITES
/project-root
/config
siteConfig.js
/src
/components
/services
/sites
/nakedSword
/guerillaPorn
/common
/public
package.json
...
Config.js file example
export const siteConfig = {
nakedSword: {
name: 'NakedSword',
routes: {
top10: getTop10PageRoute(),
originals: getOriginalsPageRoute(),
free: getFreeRoute(),
// Add more site-specific routes here
},
features: {
liveLink: true,
freeContent: true,
zine: false,
}
},
guerillaPorn: {
name: 'GuerillaPorn',
routes: {
top10: getTop10PageRoute(),
originals: getOriginalsPageRoute(),
free: getFreeRoute(),
// Add more site-specific routes here
},
features: {
liveLink: true,
freeContent: true,
zine: true,
}
},
// Add more site configurations here
};
export const getCurrentSiteConfig = () => {
const host = window.location.hostname;
if (host.includes('nakedsword')) {
return siteConfig.nakedSword;
}
if (host.includes('guerillaporn')) {
return siteConfig.guerillaPorn;
}
// Add more host checks here
return siteConfig.default;
};
Step 2: Create the Configuration Context in sites
• Set up a context to provide the configuration to your entire component tree.
src/context/SiteConfigContext.js:
import React, { createContext, useContext, useMemo } from 'react';
import { getCurrentSiteConfig } from '../../config/siteConfig'; // Adjust the import path as needed
const SiteConfigContext = createContext(null);
export const SiteConfigProvider = ({ children }) => {
const siteConfig = useMemo(() => getCurrentSiteConfig(), []);
return (
<SiteConfigContext.Provider value={siteConfig}>
{children}
</SiteConfigContext.Provider>
);
};
export const useSiteConfig = () => {
return useContext(SiteConfigContext);
};
3. Wrap Your Application with the Provider:
• Use the SiteConfigProvider to wrap your application in your entry file (e.g., index.js or App.js).
// src/index.js or src/App.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { SiteConfigProvider } from './context/SiteConfigContext'; // Adjust the import path as needed
ReactDOM.render(
<React.StrictMode>
<SiteConfigProvider>
<App />
</SiteConfigProvider>
</React.StrictMode>,
document.getElementById('root')
);
- Use the Configuration in Your Components:
• Access the configuration in your components using the useSiteConfig hook.
src/components/MainDashboardHeader/MainDashboardHeader.js:
import React from 'react';
import { Link, navigate } from "@reach/router";
import { withTranslation } from "react-i18next";
import PropTypes from 'prop-types';
import BrowseNavigation from "../../../components/BrowseNavigation/BrowseNavigation";
import MainSearch from "../../../components/MainSearch/MainSearch";
import Arrow from '../../../components/Arrow/Arrow';
import { showMyAccountPage } from "../../../services/navigation/navigation.service";
import { isUserLoggedIn, singleSignOff } from "../../../services/token-service/token.service";
import { routes } from "../../../services/navigation/navigation.service.routes";
import { isWeb } from "../../../services/util-service/util.service";
import LiveLinkNavigation from "../../../components/LiveLinkNavigation/LiveLinkNavigation";
import { MainDashboardController } from "../MainDashboardController";
import { SignInController } from "../../../controllers/sign-in-controller/sign-in.controller";
import { UsersController } from "../../../controllers/users-controller/users.controller";
import { createJoinLinkFromLastCode, links } from "../../../links";
import './MainDashboardHeader.scss';
import ApplicationLogo from "../../../components/ApplicationLogo/ApplicationLogo";
import UserAction from "../../../components/UserAction/UserAction";
import { getUserNATSCode } from '../../../services/nats-service/nats.service';
import { useSiteConfig } from '../../../context/SiteConfigContext'; // Importing shared config
const MainDashboardHeader = (props) => {
const siteConfig = useSiteConfig();
// ... (rest of the component code)
const renderSecondaryNavigation = () => {
const { renderHeaderMenu, browseConfig, t, starsPageEnabled } = props;
const { desktopSearchVisible } = this.state;
const navCls = "NavBar-Btn";
const headerOptions = (
<div className="HeaderOptions">
{!desktopSearchVisible ?
<>
<BrowseNavigation
className={navCls}
browseConfig={browseConfig}
starsPageEnabled={starsPageEnabled}
baseText={t('BrowseNavigation.browse')}
/>
<Link className={navCls}
to={routes.justAdded}
data-text={t('MainDashboardHeader.justAdded')}>
{t('MainDashboardHeader.justAdded')}
</Link>
{siteConfig.features.freeContent && (
<Link className={navCls}
onClick={this.notifyScrollTop}
key="free"
to={siteConfig.routes.free}
data-text={t('MainDashboardHeader.free')}>
{t('MainDashboardHeader.free')}
</Link>
)}
{siteConfig.features.liveLink && (
<LiveLinkNavigation
navCls="NavBar-Btn"
nsliveloggedinPage="/live"
nsliveloggedoutUrl="https://nakedswordlive.com"
linkTextKey="MainDashboardHeader.live"
/>
)}
{siteConfig.features.zine && (
<a className={navCls}
href={links.zine}
rel="noopener noreferrer"
key="zine"
target="_blank">
HUNT eZine
</a>
)}
</>
: <i className="HeaderNavCollapseIndicator fas fa-bars" />
}
{this.renderSearchEl()}
</div>
);
if (renderHeaderMenu || browseConfig?.length) {
return headerOptions;
}
return null;
};
// ... (rest of the component code)
return (
// ... (component JSX)
);
};
MainDashboardHeader.propTypes = {
className: PropTypes.string,
browseConfig: PropTypes.array,
searchOptions: PropTypes.array,
primaryNavigation: PropTypes.bool,
toggleMobileMenu: PropTypes.func,
starsPageEnabled: PropTypes.number,
handleSearchDropdownValue: PropTypes.func
};
export default withTranslation()(MainDashboardHeader);
Advantages
• Consistency: Ensures consistent configuration management across all components.
• Maintainability: Simplifies the codebase, making it easier to maintain and update.
• Flexibility: Allows you to easily switch configurations based on the current site context.
By following these steps, you can effectively implement the React Context configuration approach without any issues, even with your current Node.js and CRA setup. If you have any further questions or need additional assistance, feel free to ask!
Adding react-context into stage branch
Step 1: Work on Individual Site Branches
1. Implement and Test Changes: Apply the context-based configuration approach to the individual site branches.
2. Verify Functionality: Ensure that the changes work correctly and that site-specific configurations are applied as expected.
Step 2: Integrate Changes into the Stage Branch
1. Merge Individual Changes: Once changes are verified on the individual site branches, merge them into the stage branch.
2. Refactor Stage Branch: Strip down the stage branch to serve as a base site, if needed, focusing on core functionalities that can be shared across sites.
Example Steps for Git Workflow
Working on Individual Sites
1. Check Out Individual Branch:
git checkout -b site-nakedsword
- Implement Changes:
• Apply the context-based configuration approach.
• Refactor components to use the new context.
3. Commit Changes:
git add .
git commit -m "Refactor nakedsword site to use context-based configuration"
- Push
git push origin site-nakedsword
Integrate Changes into Stage Branch
git checkout stage
2. Merge Changes from Individual Branches:
git merge site-nakedsword
. Test and Verify: Ensure that the merged changes do not break the functionality and that the configurations are applied correctly.
- Commit and Push Stage Branch:
git add .
git commit -m "Merge site-specific changes into stage"
git push origin stage
Summary
• Refactor Components: Use the React Context to manage site-specific configurations efficiently.
• Work on Individual Branches: Apply and test changes on individual site branches first.
• Integrate into Stage Branch: Merge verified changes into the stage branch and ensure it serves as the base site if needed.
By following these steps, you can streamline the process of managing multiple sites within a single codebase, improve maintainability, and reduce the complexity of your deployment workflow. If you need further assistance or have more specific questions, please let me know!